对静态成员进行未定义的引用意味着什么?

Man*_*rse 18 c++ c++-faq

我刚刚写了一个包含一些静态数据成员的类,但现在我收到有关"未定义引用"的错误.为什么这不起作用?我究竟做错了什么?

(注意:这是Stack Overflow的C++常见问题解答的一个条目.如果你想批评在这种形式下提供常见问题解答的想法,那么发布所有这些的元数据的发布将是这样做的地方.这个问题在C++聊天室中受到监控,其中FAQ的想法一开始就出现了,所以你的答案很可能被那些提出想法的人阅读.)

Man*_*rse 27

要理解这一点,您应该对编译和链接以及声明和定义之间的差异有一个很好的理解.


考虑以下课程:

//In header file
class Example {
    static bool exampleStaticMember;
};
Run Code Online (Sandbox Code Playgroud)

在这里,exampleStaticMember声明但未定义.这意味着如果exampleStaticMember以一种意味着它必须具有地址的方式使用,那么必须有一个单独的定义.通常,类定义中的静态数据成员的声明不是该成员的定义.

所需的声明通常放在cpp文件中,该文件包含该类成员的其他定义.它必须与类定义位于同一名称空间中.该定义通常如下所示:

//In source file:
//This may optionally have an initialiser (eg "= true")
bool Example::exampleStaticMember; 
Run Code Online (Sandbox Code Playgroud)

该定义可以放在任何cpp文件中,但不应该放在带有类的头文件中,因为这可能会破坏一个定义规则.

作为一种特殊情况,如果静态成员变量是const整数或枚举类型,那么它可以在类定义中具有初始化:

//In header file
class Example {
    static const int initialised = 15;
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,仍然需要cpp文件中的定义,但不允许使用初始化器:

//In source file
//Note: no initialiser!
const int Example::initialised;
Run Code Online (Sandbox Code Playgroud)

已经初始化的静态成员可以在常量表达式中使用.

模板

对于模板的静态数据成员,情况略有不同.应该在标题中定义静态成员以及类的其余部分:

//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;
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为类模板的静态数据成员的One Definition Rule存在特定的例外.

静电的其他用途

static关键字应用于不在类范围内的函数和对象时,它可以具有非常不同的含义.

当应用于函数作用域中的对象时,它声明一个在函数的第一次执行中初始化的对象,并随后在函数调用之间保持其值.

当应用于命名空间作用域(在任何类或函数定义之外)的对象或函数时,它声明具有内部链接的对象或函数.对于对象,不推荐使用此用法,因为unnamed-namespace提供了更好的替代方法.


Con*_*ius 5

您必须实例化.cpp文件中标头中定义的静态成员.例如:

// foo.h

class foo {
    static int X;
};


// foo.cpp

#include "foo.h"

int foo::X = 0;
Run Code Online (Sandbox Code Playgroud)