关于c ++:我为什么不在头文件中初始化静态变量?


Why should I not initialize static variable in header?

本问题已经有最佳答案,请猛点这里访问。

所以,假设我有一个这样的标题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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的副本,所以我有点不明白为什么要放

1
int BaseClass::x = 10;

在CPP中。谢谢。


如果您在头中这样做,那么一旦您从多个cpp文件中包含它,就会出现多个定义错误。当您声明

1
int BaseClass::x = 10;

首先,您要定义符号baseclass::x;其次,您要告诉它初始值为10。根据一个定义规则,这在程序中只能发生一次。


如果考虑到预处理器实际上做了什么,也许更容易理解:它将所有包含的头文件的内容复制到cpp文件中,并将其传递给编译器。

现在假设您有:

1
2
3
4
5
6
7
8
9
// In a.cpp
#include <baseclass.h>

// more code

// In b.cpp
#include <baseclass.h>

// more code

预处理器展开include后,两个文件都将包含:

1
int BaseClass::x = 10;

现在,一旦两个对象文件都传递给链接器,它将看到符号BaseClass::x两次,这是一个错误。

现在,为了让它更明显,假设您将它放在一个头文件中:

1
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() { /*...*/ }

只要有一个(并且只有一个)定义,您可以拥有任意多的声明,并且链接器将确保它们都引用相同的函数或内存位置。

现在上课怎么样?类只能声明,而必须定义其成员函数和静态成员。同样,每个定义只能存在一次。

成员函数和静态成员实际上在程序的地址空间中只存在一次,而类的每个对象都存在普通成员(实例变量)。

回到您的具体问题:静态成员基本上只是全局变量,但作用域是类的名称。

希望这能帮你解决问题!


保护不会阻止多个源文件中的多个副本。它们只在一个源文件中阻止多个副本。

如果您有多个#include"base_class.h"的源文件,则会违反一个定义规则。


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