3

I am new to c++ and experimenting with classes and static variables.

I have found the solution to making the code run but I am not sure why this works and why my previous method did not

#include <iostream>

using namespace std;

class Person {
    static int id;
public:

    void createPerson() {
        id++;
        cout << id << endl;
    }

};

int Person::id = 0;


int main() {

    Person Person1;
    Person Person2;

    Person1.createPerson();
    Person2.createPerson();

}

I am wondering why I must declare the value of id outside the class. And why I cannot have something like..

class Person {
    static int id = 0;
public:

    void createPerson() {
        id++;
        cout << id << endl;
    }

};
Andrew
  • 31
  • 1

3 Answers3

4

static data members are not parts of objects, so you need to tell the compiler explicitly in which translation unit to store them by providing that definition.

Note that static data members of class templates can be defined in the header files.

In C++17 a static data member can be declared as inline, so that no out-of-line definition is necessary.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
2

Adding the inline keyword will do the job. Simply change your line to:

static inline int id = 0;

Another possibility would be, but only if your value is constant, to declare it like this:

static inline constexpr int id = 0;

This is the preferred way for declaring global constants instead of using #defines.

nada
  • 2,109
  • 2
  • 16
  • 23
  • Since `id` is supposed to be incremented, the `constexpr` part is not really relevant to the question. – Max Langhof Sep 05 '19 at 11:17
  • @MaxLanghof Never miss an opportunity to mention `constexpr` to learners – nada Sep 05 '19 at 11:33
  • Thank you for the response! That helped in learning a new way to deal with this problem I had and I will now definitely do some looking into constexpr – Andrew Sep 06 '19 at 13:26
0

Within a class definition static data members are declared bur not defined. So you may even to use a non-complete type in a declaration of a static data member inside a class definition.

For example

struct A
{
    static int a[];
};

int A::a[10];

Here in this example the declaration of the data member a within the class definition has an incomplete array type (the number of elements of the array is unknown).

Starting from C++ 17 you may declare a static data member as an inline member. For example

class Person {
    inline static int id = 0;
public:

    void createPerson() {
        id++;
        cout << id << endl;
    }
};

In this case you may initialize it in the declaration inside the class definition.

Otherwise you may initialize a static data member within a class definition only if it is declared as having an integral type and has the qualifier const or the specifier constexpr (in the last case the static data member will be an inline declaration).

But if a static data member is declared as a const object nevertheless you have to define it outside the class if for example you will try to get the address of the static data member. For example this code is invalid

#include <iostream>
using namespace std;

class Person {
    const static int id = 0;
public:

    void createPerson() {
        cout << &id << endl;
    }

};

int main() 
{
    Person Person1;
    Person Person2;

    Person1.createPerson();
    Person2.createPerson();
}

As there is the address of the static data member is taken then you have to define the static data member.

#include <iostream>
using namespace std;

class Person {
    const static int id = 0;
public:

    void createPerson() {
        cout << &id << endl;
    }

};

const int Person::id;

int main() 
{
    Person Person1;
    Person Person2;

    Person1.createPerson();
    Person2.createPerson();
}

This program will compile.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335