class X {
static int i;
// some other function, variable declaration, cons, dest
};
int X :: i ; **(!)**
为什么我必须写那(!)行,总是?
如果我不写,编译器无法完成内部链接,所以它给出(我假设)链接器错误。为什么 ?
因为这就是静态成员的工作方式。它们除了直接存在于类中的实例之外。
您不能在类中定义它们,因为那样的话,每个使用您的类的实现文件都会有多个定义。
因此,您需要选择一个实际定义静态成员的实现文件。
这被称为单一定义规则。每个全局对象(技术上,每个具有外部链接的对象)都必须在一个源文件中定义(技术上,在一个翻译单元中)。但是,它可以声明任意多次。
通常,类定义将位于头文件中,该文件可能包含在许多源文件中。所以不能在那里定义任何静态成员,只能声明,否则会有多个定义。您必须在一个源文件中单独定义静态成员,以便链接器准确找到一个定义。这就是标记的行的(!)
作用。
静态变量必须在 TU(即 cpp 文件)中定义(与声明相反)。
如果它只是声明而不定义,则不会为其分配存储空间,因此链接器无法找到它。
static int i;
是一个声明,即告诉编译器在某些翻译单元(=>.cpp
文件)中将实际定义这样的静态字段。需要让编译器知道存在这样的变量,并让您在声明它的每个翻译单元中使用它。
int X :: i;
相反,它是一个定义,它告诉编译器实际为该变量提供空间。它必须保留在一个 中.cpp
,否则每个翻译单元都会为它自己提供一些空间(并且链接器会抱怨)。
extern
这与为什么对于全局变量,您需要在每个需要使用它的文件中声明(通常放在头文件中)并在定义它的单个文件中进行正常定义的原因完全相同.cpp
。
C++ 明确区分了声明和定义。你需要告诉编译器两件事:
这通常一步完成,即一个局部 int 变量:
void f() {
int x; // Declaration and definition.
}
由于 .hpp 头文件可以包含在许多 .cpp 文件中,因此您的(!)
行必须驻留在单个特定的 .cpp 上,通常在任何头文件之外。
静态类成员在所有类实例之间共享(在内存中只有一个位置存在此类变量),因此static int i;
在类声明中仅表示变量声明-您需要在某处为该变量分配内存-您需要定义它-这是在实现文件中完成的int X::i;
类定义只定义成员,但它必须存在于单个编译单元(即.cpp 文件)中。
您可以说它是“单一定义规则”的一部分。