我已经阅读了很多关于静态变量的文档。这是一个我不明白的例子。假设类中的静态变量声明如下:
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_nvalue
,为什么需要再次重新定义它?如果我们之前没有写int
,则会显示错误。为什么会这样?
答案 0 :(得分:2)
这是C ++的本质,当你定义一些东西时,你必须指定它的确切类型,即使你之前有过声明。所有变量和函数都是如此。
旁注:您不会重新定义它,这会导致编译错误。你只需定义它。
答案 1 :(得分:2)
在通常的C ++程序中,您的类在头文件中定义,所有头文件都包含在使用它们的所有源文件中。因此,如果它以您期望的方式工作,则每个源文件将拥有其自己的静态变量副本,而实际上它们应该共享一个副本。这将违反单一定义规则......每个对象只能定义为存在于一个地方。
因此,声明类中的变量只是向编译器宣告某个地方会有一个具有此名称和类型的变量;它不会指示编译器为其分配空间。此时,变量在包含它的任何源文件中保持未定义。然后,在一个特定的源文件[通常是该特定类的实现文件]中,提供实际定义int Something::s_nValue;
行。这要求编译器为变量分配空间,以便它只存在于那个位置,并且当你将所有目标文件链接在一起时没有歧义。
答案 2 :(得分:2)
声明某些内容与定义某些内容不同。有时您可以同时执行这两种操作,但无论哪种方式,您都需要声明和定义某些内容。
为什么?
嗯,因为标准是这样说的,但为什么标准会这样说呢?
它与编译和链接的工作方式有关。如果我有几个源文件a.cpp
和b.cpp
以及几个头文件a.h
和b.h
,那么我会想要编译它们。通常,您单独编译所有源文件以获取a.o
和b.o
,然后在最后将它们链接在一起以获得最终程序。
说我们有:
// 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
基本上只是将其他文件粘贴到包含文件中。因此,编译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; }
应该{{1}}和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
中。只要定义一次就无所谓了。
答案 3 :(得分:1)
欢迎来到C ++的精彩世界:声明VS.定义。在您发布的代码中,有一个声明和一个定义。 声明为某些符号指定了名称和类型。 定义给出符号“值”。
class Something
{
public:
// declaration.
static int s_nValue;
};
// definition.
int Something::s_nValue = 1;
此过程类似于功能原型:
// declaration.
void f ( int i );
// definition.
void f ( int i )
{
std::cout << i << std::endl;
// ...
}
为了增加混淆,一些陈述同时进行。例如,如果您没有声明一个函数,那么该定义也可以作为一个声明(这对于静态变量是不可能的,就像您发布的Something::s_nValue
一样)。
答案 4 :(得分:1)
这与C中的情况类似,您可以在头文件中执行以下操作:
extern int Something_s_nValue;
你要做的源文件是:
int Something_s_nValue;
第一部分是头文件中的声明,第二部分是源文件中的定义。