为什么我不应该在头文件中初始化静态变量?

时间:2014-04-04 17:55:07

标签: c++

所以,让我们说我有这样的标题:

#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。感谢。

4 个答案:

答案 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)

因为如果您在标题中初始化它,如果您多次包含标题,则可能会在多个位置定义它。这将导致链接器错误