我刚写了一个包含一些静态数据成员的类,但现在我收到有关“未定义引用”的错误。为什么这不起作用?我做错了什么?
<子> (注意:这是Stack Overflow's C++ FAQ的一个条目。如果您想批评在此表单中提供常见问题解答的想法,那么the posting on meta that started all this就是这样做的地方。在C++ chatroom中监控了这个问题,首先是FAQ的想法,所以你的答案很可能会被那些提出想法的人阅读。) 子>
答案 0 :(得分:26)
要理解这一点,您应该对compiling and linking以及declarations and definitions之间的差异有充分的了解。
考虑以下课程:
//In header file
class Example {
static bool exampleStaticMember;
};
此处,exampleStaticMember
已声明但未定义。这意味着如果exampleStaticMember
的使用方式意味着它必须具有地址,那么必须有一个单独的定义。通常,类定义中的静态数据成员的声明不是该成员的定义。
所需声明通常放在cpp文件中,该文件包含该类成员的其他定义。它必须与类定义位于同一名称空间中。该定义通常如下所示:
//In source file:
//This may optionally have an initialiser (eg "= true")
bool Example::exampleStaticMember;
定义可以放在任何cpp文件中,但不应该放在带有类的标题中,因为这可能会破坏One Definition Rule。
作为一种特殊情况,如果静态成员变量是const整数或枚举类型,那么它可以在类定义中具有初始化:
//In header file
class Example {
static const int initialised = 15;
};
在这种情况下,仍然需要cpp文件中的定义,但不允许使用初始化器:
//In source file
//Note: no initialiser!
const int Example::initialised;
已经初始化的静态成员可以在常量表达式中使用。
<强>模板强>
对于模板的静态数据成员,情况略有不同。应该在标题中定义静态成员以及类的其余部分:
//In header file
template<typename T>
class Example {
static int exampleInt;
static T exampleT;
}
template<typename T> int Example<T>::exampleInt;
template<typename T> T Example<T>::exampleT;
这是有效的,因为类模板的静态数据成员的One Definition Rule存在特定的例外。
静态的其他用途
当static
关键字应用于不在类范围内的函数和对象时,它可能具有非常不同的含义。
当应用于函数作用域中的对象时,它声明一个在第一次执行函数时初始化的对象,并随后在函数调用之间保持其值。
当应用于命名空间范围内的对象或函数(在任何类或函数定义之外)时,它使用internal linkage声明对象或函数。对象不推荐使用此用法,因为unnamed-namespace提供了更好的选择。
答案 1 :(得分:5)
您必须实例化.cpp文件中标头中定义的静态成员。例如:
// foo.h
class foo {
static int X;
};
// foo.cpp
#include "foo.h"
int foo::X = 0;