为什么我不应该初始化标头中的静态变量

Why should I not initialize static variable in header?

本文关键字:静态 变量 不应该 初始化 为什么      更新时间:2023-10-16

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

#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中。

如果在标头中执行此操作,则只要从多个 CPP 文件中包含它,就会收到多个定义错误。 当你声明时,你实际上是在告诉编译器两件事

int BaseClass::x = 10;

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

如果您考虑预处理器的实际作用,也许更容易理解:它将所有包含的头文件的内容复制到 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() { /*...*/ }

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

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

成员

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

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

希望这能为您解决问题!

防护不会阻止多个源文件中的多个副本。它们仅防止一个源文件中的多个副本。

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

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