为什么我不应该初始化标头中的静态变量
Why should I not initialize static variable in header?
所以,假设我有一个这样的标题:
#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"
的源文件,则将违反一个定义规则。
因为如果在标头中初始化它,则在多次包含标头时,可能会在多个位置定义它。这将导致链接器错误
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 模板基类中的静态变量
- 类和静态变量
- 不同作用域中的静态变量和全局变量
- 静态变量声明和定义
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 在类中继承静态变量?
- "local scope"中的 C++ 初始化静态变量
- 使用静态变量的递归调用的不同输出
- 复制文件流C++静态变量
- 跨模板化函数编译的静态变量
- C++编译器是否优化了顺序静态变量读取?
- C++,每个循环初始化一个新的静态变量
- (为什么)我们可以在初始化中将非静态类成员分配给静态变量吗?
- 这些语句是否等效(静态变量、常量变量和泛型)
- 程序如何知道静态变量是否需要初始化?
- 类外的静态变量实例化
- 无法解析静态变量
- 函数局部静态变量:从性能角度来看的优点/缺点
- 访问从 CPP 文件到其他头文件的静态变量