简体   繁体   English

关于静态变量的问题

[英]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? 我的问题是:我们已经在类中声明了s_nvalue ,为什么需要再次重新定义它? If we don't write int before, it will show an error. 如果我们之前不写int ,则会显示错误。 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. 这是C ++的本质,当你定义一些东西时,你必须指定它的确切类型,即使你以前有过声明。 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. 在通常的C ++程序中,您的类在标头中定义,所有标头都包含在使用它们的所有源文件中。 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; 然后,在一个特定的源文件[通常是该特定类的实现文件]中,提供一个实际的定义, 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. 如果我有几个源文件, a.cppb.cpp以及几个头文件, ahbh然后我会想要编译它们。 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. 通常,您单独编译所有源文件以获取aobo ,然后在最后将它们链接在一起以获取最终程序。

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. 请记住, #include实际上只是粘贴包含文件中的其他文件。 So all the compiler sees when we compile a.cpp and b.cpp is: 因此,所有编译器在编译a.cppb.cpp时都会看到:

// 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? A::nB::n进入哪个目标文件? ao or bo ? ao还是bo It's declared in both a.cpp and b.cpp so the compiler has no idea where to put it. 它在a.cppb.cpp声明,因此编译器不知道在哪里放置它。 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 . 值得指出的是,您可以将两者都放在a.cpp或两者都放在b.cpp It doesn't matter, as long as it is defined exactly once. 无关紧要,只要它只定义一次即可。

Welcome to the wonderful world of C++: declarations VS. 欢迎来到C ++的精彩世界:声明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). 例如,如果您没有声明一个函数,那么该定义也可以作为声明(这对于静态变量是不可能的,就像您发布的Something::s_nValue情况一样)。

This is similar to the case in C, where in your header file you would do: 这类似于C中的情况,您可以在头文件中执行以下操作:

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. 第一部分是头文件中的声明,第二部分是源文件中的定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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