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

use*_*846 9 c++

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

#ifndef BASECLASS_H
#define BASECLASS_H

class BaseClass
{
    public:
        static int getX(){return x;}
    private:
        static int x;
};

int BaseClass::x = 10;

#endif
Run Code Online (Sandbox Code Playgroud)

我多次听说过我不应该在头文件中初始化静态变量,而是在cpp中.但是因为有守卫,所以应该只有一个BaseClass :: x副本.所以我有点不明白为什么要放

int BaseClass::x = 10; 
Run Code Online (Sandbox Code Playgroud)

在cpp.谢谢.

Nat*_*one 10

如果在标题中执行此操作,则只要从多个CPP文件中包含多个定义错误,就会出现多个定义错误.在声明时,你真的告诉编译器两件事

int BaseClass::x = 10;
Run Code Online (Sandbox Code Playgroud)

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

  • @ user3496846不,你只需要一个由(至少)两个cpp文件组成的程序,这两个文件都包含你的标题. (2认同)

let*_*tar 5

如果您考虑预处理器实际执行的操作,可能会更容易理解:它将所有包含的头文件的内容复制到cpp文件中并将其传递给编译器.

现在让我们说你有:

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

// more code

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

// more code
Run Code Online (Sandbox Code Playgroud)

预处理器扩展包含后,两个文件将包含:

int BaseClass::x = 10; 
Run Code Online (Sandbox Code Playgroud)

现在,只要两个目标文件都传递给链接器,它就会看到符号BaseClass::x两次 - 这是一个错误.

现在,为了使它更加明显,想象一下你会把它放在一个头文件中:

int aGlobalVariable = 10;
Run Code Online (Sandbox Code Playgroud)

然后将它包含在两个不同的cpp文件中,这两个文件都应链接到一个可执行文件中.如果从链接器的角度来看,它实际上与您的示例没有任何不同.

为什么这不是类声明的问题?

声明定义之间存在差异.只有后者会引起问题.例如,以下所有都是声明:

  • extern int a;
  • void foo(int a);
  • class Foo { int bar(); };

而这些是定义:

  • int a;
  • int b = 10;
  • void foo(int a) { /*..*/ }
  • int Foo::bar() { /*...*/ }

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

那课怎么样?只能声明类,而必须定义它们的成员函数和静态成员.同样,每个定义可能只存在一次.

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

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

希望这能为您解决问题!