Home > Enterprise >  Why C static data members are needed to define but non-static data members do not?
Why C static data members are needed to define but non-static data members do not?

Time:11-22

I am trying to understand the difference between the declaration & definition of static and non-static data members. Apology, if I am fundamentally miss understood concepts. Your explanations are highly appreciated.

Code Trying to understand

class A
{
public:
    int ns; // declare non-static data member.
    static int s; // declare static data member. 
    void foo();
    
};
 
int A::s; // define non-static data member.
// int A::ns; //This gives an error if defined.

void A::foo()
{
    ns = 10;
    s = 5; // if s is not defined this gives an error 'undefined reference'
}

CodePudding user response:

static variables belongs to the class definition. non-static variables belong to the instances created with the class definition.

int main()
{
    A::s = 5; // this is ok

    A a;
    a.ns = 5 // this is also ok
}

CodePudding user response:

When you declare something, you're telling the compiler that the name being declared exists and what kind of name it is (type, variable, function, etc.) The definition could be with the declaration (as with your class A) or be elsewhere—the compiler and linker will have to connect the two later.

The key point of a variable or function definition is that it tells the compiler and linker where this variable/function will live. If you have a variable, there needs to be a place in memory for it. If you have a function, there needs to be a place in the binary containing the function's instructions.

For non-static data members, the declaration is also the definition. That is, you're giving them a place to live¹. This place is within each instance of the class. Every time you make a new A object, it comes with an ns as part of it.

Static data members, on the other hand, have no associated object. Without a definition, you've got a situation where you have N instances of A all sharing the same s, but nowhere to put s. Therefore, C makes you choose one translation unit for it via a definition, most often the source file that acommpanies that header.

You could argue that the compiler should just pick one instance for it, but this won't work for various reasons, one being that you can use static data members before ever creating an instance, after the last instance is gone, or without having instances at all.

Now you might wonder why the compiler and linker still can't just figure it out on their own, and... that's actually pretty much what happens if you slap an inline on the variable or function. You can end up with multiple definitions, but only one will be chosen.


1: Giving them a place to live is a little beside the point here. All the compiler needs to know when it creates an object of that class is how much space to give it and which parts of that space are which data members. You could think of it as the compiler doing the definition part for you since there's only one place that data member could possibly live.

CodePudding user response:

static members are essentially global variables with a special name and access rules tied to the class. Hence, they inherit all the problems for usual global variables. Namely, in the whole C program (which is the union of all translation units aka .cpp files) there should be exactly one definition of each global variable, no more.

You can think of "variable definition" as "the place which will allocate memory for the variable".

However, classes are typically defined in a header file (.h/.hpp/etc) which is included in multiple translation units. So it's up to the programmer to specify which translation unit actually defines the variable. Note that since C 17 we have the inline keyword which places this burden on a compiler, look for "inline variables". The naming is weird for historical reasons.

However, non-static members do not really exist until you create an instance of the class, i.e. an object. And it's the object lifetime and storage duration which define how each individual member is created/stored/destroyed. So there is no need to actually define them anywhere outside of the class.

  • Related