所以,让我们说我有这样的标题:
#ifndef BASECLASS_H
#define BASECLASS_H
class BaseClass
{
public:
static int getX(){return x;}
private:
static int x;
};
int BaseClass::x = 10;
#endif
我多次听说过我不应该在头文件中初始化静态变量,而是在cpp中。但是因为有守卫,所以应该只有一个BaseClass :: x副本。所以我有点不明白我为什么要把
int BaseClass::x = 10;
在cpp。感谢。
答案 0 :(得分:10)
如果您在标题中执行此操作,则只要从多个CPP文件中包含多个定义错误,您就会收到多个定义错误。当你声明
时,你真的告诉编译器两件事int BaseClass::x = 10;
首先,您要定义符号BaseClass :: x;第二,你告诉它你希望它的初始值为10.根据One Definition Rule,这只能在你的程序中发生一次。
答案 1 :(得分:5)
如果您考虑预处理器实际执行的操作,可能会更容易理解:它会将所有包含的头文件的内容复制到cpp文件中并将其传递给编译器。
现在让我们说你有:
// In a.cpp
#include <baseclass.h>
// more code
// In b.cpp
#include <baseclass.h>
// more code
预处理器扩展包含后,两个文件都将包含:
int BaseClass::x = 10;
现在,只要两个目标文件都传递给链接器,它就会看到符号BaseClass::x
两次 - 这是一个错误。
现在,为了使它更加明显,想象一下你会把它放在一个头文件中:
int aGlobalVariable = 10;
然后将其包含在两个不同的cpp文件中,这两个文件都应链接到一个可执行文件中。如果从链接器的角度来看,它实际上与您的示例没有任何不同。
为什么这不是类声明的问题?
声明和定义之间存在差异。只有后者会引起问题。例如,以下所有都是声明:
extern int a;
void foo(int a);
class Foo { int bar(); };
这些是定义:
int a;
int b = 10;
void foo(int a) { /*..*/ }
int Foo::bar() { /*...*/ }
只要有一个(并且只有一个)定义,您可以拥有与您一样多的声明,并且链接器将确保它们都引用相同的函数或内存位置。
现在课程怎么样?只能声明类,而必须定义它们的成员函数和静态成员。同样,每个定义可能只存在一次。
成员函数和静态成员实际上只存在于程序的地址空间中一次,而普通成员(实例变量)存在于该类的每个对象中。
回到你的具体问题:静态成员基本上只是全局变量,但是作用于类&#39;名。
希望这能为你解决问题!
答案 2 :(得分:4)
警卫不会阻止多个源文件中的多个副本。它们只能阻止一个源文件中的多个副本。
如果您有多个#include "base_class.h"
的源文件,则会违反一个定义规则。
答案 3 :(得分:2)
因为如果您在标题中初始化它,如果您多次包含标题,则可能会在多个位置定义它。这将导致链接器错误