Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于静态变量的问题_C++_Oop - Fatal编程技术网

C++ 关于静态变量的问题

C++ 关于静态变量的问题,c++,oop,C++,Oop,我已经阅读了许多关于静态变量的文档。这里有一个我不理解的例子。假设类中的静态变量声明如下: 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

我已经阅读了许多关于静态变量的文档。这里有一个我不理解的例子。假设类中的静态变量声明如下:

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;    
}
分类
{
公众:
静态整数s_n值;
};
int Something::s_nValue=1;
int main()
{    
某物:s_nValue=2;

STD::CUT

这是C++的一个性质,当你定义了一些东西时,你必须指定它的确切类型,即使你以前有一个声明。对于所有的变量和函数来说都是这样。


旁注:你不需要重新定义它,那会导致编译错误。你只需要定义它。

欢迎来到C++的奇妙世界:声明与定义。在你发布的代码中,有一个声明和一个定义。声明给一些符号一个名称和类型。定义给符号一个“值”

此过程类似于功能原型:

// declaration.
void f ( int i );

// definition.
void f ( int i )
{
    std::cout << i << std::endl;
    // ...
}
//声明。
无效f(int i);
//定义。
无效f(内部i)
{

STD::CUT< P>在一个通常的C++程序中,你的类是在所有使用的源文件中包含的报头中定义的。如果它按预期的方式工作,每个源文件都有它自己的静态变量拷贝,在实际情况下它们应该共享一个副本。这将违反一个定义规则…ch对象只能定义为存在于一个位置


因此,在类中声明变量只是向编译器宣布某个地方将有一个具有此名称和类型的变量;它不会指示编译器为其分配空间。此时,该变量在包含它的任何源文件中保持未定义状态。然后,在一个特定的源文件中[通常是该特定类的实现文件],您提供了一个实际的定义,即
int Something::s\u nValue;
行。这要求编译器为变量分配空间,使其仅存在于该位置,并且在将所有对象文件链接在一起时不会出现歧义。

这与C中的情况类似,在头文件中,您将执行以下操作:

extern int Something_s_nValue;
int Something_s_nValue;
您可以使用源文件执行以下操作:

extern int Something_s_nValue;
int Something_s_nValue;

第一部分是头文件中的声明,第二部分是源文件中的定义。

声明某物与定义某物不同。有时可以同时执行这两项操作,但无论哪种方式,都需要同时声明和定义某物

为什么?

因为标准上这么说,但为什么标准上这么说呢

这与编译和链接的工作方式有关。如果我有两个源文件,
a.cpp
b.cpp
,还有两个头文件,
a.h
b.h
,那么我就要编译它们。通常,你单独编译所有源文件,以获得
a.o
b.o
,然后链接到t最后,齐聚一堂,完成你的最终计划

假设我们有:

// 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; }
请记住,
#include
实际上只是将另一个文件粘贴到include文件中。因此,当我们编译
a.cpp
b.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; }
哪个对象文件应该
A::n
B::n
放入?
A.o
B.o
?它在
A.cpp
B.cpp
中声明,因此编译器不知道放在哪里。如果同时放在这两个文件中,您将定义两次,编译器将不知道使用哪个文件(在这种情况下,链接器会给您一个“多重定义符号”错误)

这就是为什么我们需要一个定义。这个定义告诉我们应该把它放在哪个对象文件中

// 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; }

值得指出的是,您可以将两者都放在
a.cpp
b.cpp
中。这没关系,只要定义一次即可。

因为这是该语言想要的。可能的重复