简体   繁体   中英

Question about static variable

I have read many documentation about static variables. Here is one example which I didn't understand. Suppose that static variable in a class is declared like this:

class Something
{
  public:
    static int s_nValue;   
};

int Something::s_nValue = 1;

int main()    
{    
    Something::s_nValue = 2;    
    std::cout << Something::s_nValue;    
    return 0;    
}

My question is: we have declared s_nvalue in class already, and why it is required to redefine it again? If we don't write int before, it will show an error. Why is it so?

This is a nature of C++, when you define something you have to specify it's exact type, even if you had a declaration previously. This is true for all variables and functions.

Sidenote: you don't redefine it, that would cause a compilation error. You just define it.

In a usual C++ program, your classes are defined in headers that get included by all the source files that use them. So if it worked the way you expect, each source file would have its own copy of that static variable, when in reality they are supposed to all share one copy. This would be a violation of the one-definition-rule... each object can only be defined as existing in one place.

So declaring the variable within the class simply announces to the compiler that somewhere there will be a variable with this name and type; it does not instruct the compiler to allocate space for it. At this point, the variable remains undefined in any source files that include it. Then, within one specific source file [usually the implementation file for that particular class], you provide an actual definition, the int Something::s_nValue; line. That asks the compiler to allocate space for the variable, so that it only exists in that one location and there is no ambiguity when you go to link all your object files together.

Declaring something is not the same as defining something. Sometimes you can do both at the same time, but either way you need to both declare and define something.

Why?

Well, because the standard says so, but why does the standard say so?

It has to do with how compiling and linking works. If I have a couple of source files, a.cpp and b.cpp and a couple of header files, ah and bh then I'll want to compile them. Generally, you compile all the source files individually to get ao and bo and then link them together at the end to get your final program.

Say we had:

// a.h =========================
class A { static int n; };  

// b.h =========================
class B { static int n; };

// a.cpp =======================
#include "a.h"
#include "b.h"

int foo() { return A::n + B::n; }

// b.cpp =======================
#include "a.h"
#include "b.h"

int bar() { return A::n - B::n; }

Remember that an #include essentially just pastes the other file inside the including file. So all the compiler sees when we compile a.cpp and b.cpp is:

// a.cpp =======================
class A { static int n; };
class B { static int n; };

int foo() { return A::n + B::n; }

// b.cpp =======================
class A { static int n; };
class B { static int n; };

int bar() { return A::n - B::n; }

Which object file should A::n and B::n go in? ao or bo ? It's declared in both a.cpp and b.cpp so the compiler has no idea where to put it. If you put it in both then you'll define it twice, and the compiler won't know which to use (in that case, the linker would give you a 'multiply defined symbol' error).

That's why we need a definition. The definition tells us which object file to put it in.

// a.cpp =======================
#include "a.h"
#include "b.h"

int A::n = 0; // A::n goes in a.o

int foo() { return A::n + B::n; }

// b.cpp =======================
#include "a.h"
#include "b.h"

int B::n = 0; // B::n goes in b.o

int bar() { return A::n - B::n; }

It's worth pointing out that you could have put both in a.cpp or both in b.cpp . It doesn't matter, as long as it is defined exactly once.

Welcome to the wonderful world of C++: declarations VS. definitions. In the code you posted, there is a declaration and a definition. A declaration gives some symbol a name and a type. A definition gives a symbol a "value".

class Something
{
public:
    // declaration.
    static int s_nValue;   
};

// definition.
int Something::s_nValue = 1;

This process is similar to function prototyping:

// declaration.
void f ( int i );

// definition.
void f ( int i )
{
    std::cout << i << std::endl;
    // ...
}

To add to the confusion, some statements do both at the same time. For example, if you don't declare a function, the definition also acts as a declaration (this is not possible for static variables, as in the Something::s_nValue case you posted).

This is similar to the case in C, where in your header file you would do:

extern int Something_s_nValue;

And you your source file you would do:

int Something_s_nValue;

The first part is the declaration which goes in your header file, and the second part is the definition which goes in your source file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM