C++中的静态成员
在一个类的定义中,关键字 static 声明一个不属于类实例的成员。
一些细节
如果类定义中某个成员的声明说明符包含关键字 static,那么它就是类的静态成员。静态成员的名称不能和包含的类相同。
需要注意的是,在类定义中声明的静态变量是一个声明而不是定义,并且成员可以是一个不完整类型(除了void),类型也可以是成员声明所在的类型,例如如下代码:
struct Foo;
struct S
{
static int a[]; // 这是一个声明,且是不完整类型
static Foo x; // 这是一个声明,且是不完整类型
static S s; // 声明,成员的类型为S,为成员所在的类型,因为S是一个不完整的类型,所以s也是一个不完整的类型
};
int S::a[10]; // 定义,完整的类型
struct Foo {};
Foo S::x; // 定义,完整的类型
S S::s; // 定义,完整的类型
如果声明使用了 constexpr 或者 inline(从C++17开始),那么成员必须拥有完成类型。
静态成员遵循类成员访问规则(class member rules)。
静态成员函数
静态成员函数不能是 const,volatile,virtual,引用限定(ref-qualified)。
静态数据成员
静态数据在整个程序中只有一个实例,且生命周期为静态存储周期,但是如果使用了 thread_local 关键字,那么每个线程都会有一个该对象,且生命周期为线程存储周期。
内联的静态成员
从 C++17 开始,静态成员可以是内联的,如下代码所示:
struct X
{
inline static int a = 10;
}
一个内联的静态数据成员可以被定义在类中,且可以拥有初始化器。
常量静态成员
如果一个整形或者枚举类型的静态数据成员被声明为 const,那么可以在类中直接通过一个常量表达式初始化它,例如如下代码:
struct X
{
const static int n = 1;
const static int m{2};
const static int k;
};
const int X::k = 3;
从 C++11 开始,如果(LiteralType )静态成员被声明为 constexpr,那么必须在类定义中通过常量表达式初始化器初始化它。如果一个 const 或者 constexpr 静态数据成员被 odr-used 了,那么在命名空间作用域仍然需要一个定义,但是它不能有初始化器。
但是从 C++17开始,如果静态常量数据成员是内联的 inline,那么可以不需要定义,需要注意的是,constexpr 已经暗含了 inline,因此一个 constexpr 静态成员也可以不需要定义,例如如下代码:
struct X
{
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m ord 使用
const int X::n; // 所以X::n需要一个定义
constexpr int X::m; //但是X::m不需要,虽然也允许

浙公网安备 33010602011771号