2011-09-25 52 views
2

我已经阅读了很多关于静态变量的文档。这是我不明白的一个例子。假设在一个类的静态变量声明如下:关于静态变量的问题

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,它会显示错误。为什么这样?

+3

因为这就是语言所需。 –

+2

[C++静态成员变量及其初始化]的可能重复(http://stackoverflow.com/questions/4547660/c-static-member-variable-and-its-initialization) –

回答

2

在通常的C++程序中,您的类定义在所有使用它们的源文件包含的标头中。因此,如果它按照您期望的方式工作,则每个源文件都将拥有自己的该静态变量的副本,但实际上它们应该共享一个副本。这将违反单定义规则......每个对象只能被定义为存在于一个地方。

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

2

这是C++的本质,当你定义一些你必须指定的确切类型时,即使你之前有过一个声明。所有变量和函数都是如此。

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

1

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

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例子那样)。

1

这类似于C,在你的头文件,你会做的情况:

extern int Something_s_nValue; 

你你的源文件,你会怎么做:

int Something_s_nValue; 

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

2

声明某事与定义某事不同。有时候你可以同时做两个事情,但是你需要同时声明和定义一些事情。

为什么?

那么,因为标准这么说,但标准为什么这么说呢?

它与编译和链接工作的方式有关。如果我有几个源文件,a.cppb.cpp和几个头文件,a.hb.h然后我想编译它们。一般来说,您可以单独编译所有源文件以获得a.ob.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.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; } 

哪个对象文件应该A::nB::n进去? a.ob.o?它在a.cppb.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; } 

值得指出的是,你可以在b.cpp已经把无论是在a.cpp或两者兼而有之。没关系,只要定义一次。