命名空间
变体
操作

static 成员

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
 
 

在类定义中,关键字 static 声明与类实例无关的成员。

在类定义之外,它具有不同的含义:请参阅 存储持续时间.

内容

[编辑] 语法

静态成员的声明是 成员声明,其声明说明符包含关键字 static。关键字 static 通常出现在其他说明符之前(这就是语法通常非正式地描述为 static 数据成员static 成员函数 的原因),但它可以出现在说明符序列中的任何位置。

任何静态数据成员和静态成员函数的名称必须不同于包含类的名称。

[编辑] 解释

类的静态成员与类的对象无关:它们是具有静态或线程(自 C++11 起) 存储持续时间的独立变量或普通函数。

关键字 static 仅与类定义内部的静态成员声明一起使用,而不用于该静态成员的定义。

class X { static int n; }; // declaration (uses 'static')
int X::n = 1;              // definition (does not use 'static')

类主体内部的声明不是定义,并且可以声明成员为 不完全类型(除了 void 外),包括声明成员的类型。

struct Foo;
 
struct S
{
    static int a[]; // declaration, incomplete type
    static Foo x;   // declaration, incomplete type
    static S s;     // declaration, incomplete type (inside its own definition)
};
 
int S::a[10]; // definition, complete type
struct Foo {};
Foo S::x;     // definition, complete type
S S::s;       // definition, complete type

但是,如果声明使用 constexprinline(自 C++17 起) 指定符,则成员必须声明为具有完整类型。

(自 C++11 起)

要引用类 T 的静态成员 m,可以使用两种形式:限定名称 T::m 或成员访问表达式 E.mE->m,其中 E 是分别计算为 TT* 的表达式。在相同的类范围中,限定符是不必要的。

struct X
{
    static void f(); // declaration
    static int n;    // declaration
};
 
X g() { return X(); } // some function returning X
 
void f()
{
    X::f();  // X::f is a qualified name of static member function
    g().f(); // g().f is member access expression referring to a static member function
}
 
int X::n = 7; // definition
 
void X::f() // definition
{
    n = 1; // X::n is accessible as just n in this scope
}

静态成员遵循 类成员访问规则 (私有、受保护、公共).

[编辑] 静态成员函数

静态成员函数与任何对象无关。当调用时,它们没有 this 指针。

静态成员函数不能为 virtualconstvolatile引用限定 的。

静态成员函数的地址可以存储在普通 函数指针 中,但不能存储在 成员函数指针 中。

[编辑] 静态数据成员

静态数据成员不与任何对象关联。即使没有定义类的任何对象,它们也存在。在整个程序中,静态数据成员只有一个实例,其具有静态 存储期限,除非使用关键字 thread_local,在这种情况下,每个线程都有一个这样的对象,具有线程存储期限(自 C++11 起).

静态数据成员不能是 mutable.

命名空间作用域中类的静态数据成员具有 外部链接,如果该类本身具有外部链接(不是 无名命名空间 的成员)。局部类(在函数内定义的类)和无名类,包括无名类的成员类,不能具有静态数据成员。

静态数据成员可以声明为 inline。内联静态数据成员可以在类定义中定义,并且可以指定初始化程序。它不需要类外定义

struct X
{
    inline static int fully_usable = 1; // No out-of-class definition required, ODR-usable
    inline static const std::string class_name{"X"}; // Likewise
 
    static const int non_addressable = 1; // C.f. non-inline constants, usable
                                          // for its value, but not ODR-usable
    // static const std::string class_name{"X"}; // Non-integral declaration of this
                                                 // form is disallowed entirely
};
(自 C++17 起)

[编辑] 常量静态成员

如果整型或枚举类型的静态数据成员声明为 const(而不是 volatile),则可以使用 初始化程序 在类定义中直接进行初始化,其中每个表达式都是一个 常量表达式

struct X
{
    const static int n = 1;
    const static int m{2}; // since C++11
    const static int k;
};
const int X::k = 3;

如果 LiteralType 的静态数据成员声明为 constexpr,则必须在类定义中使用初始化程序进行初始化,其中每个表达式都是一个常量表达式

struct X
{
    constexpr static int arr[] = { 1, 2, 3 };        // OK
    constexpr static std::complex<double> n = {1,2}; // OK
    constexpr static int k; // Error: constexpr static requires an initializer
};
(自 C++11 起)

如果常量 非内联(自 C++17 起) 静态数据成员 或 constexpr 静态数据成员(自 C++11 起)(直到 C++17)ODR-使用,则仍然需要在命名空间作用域中进行定义,但不能使用初始化程序。

一个 constexpr 静态数据成员隐式为 inline,不需要在命名空间作用域中重新声明。这种不使用初始化程序的重新声明(以前是必需的)仍然允许,但已弃用。

(自 C++17 起)
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 are ODR-used
const int X::n;             // … so a definition is necessary
constexpr int X::m;         // … (except for X::m in C++17)

[编辑] 关键字

static

[编辑] 缺陷报告

以下更改行为的缺陷报告已追溯应用于以前发布的 C++ 标准。

DR 应用于 已发布的行为 正确行为
CWG 194 C++98 (static) 成员函数名可以与类名相同 添加命名限制(包括
非静态成员函数)

[编辑] 参考文献

  • C++23 标准 (ISO/IEC 14882:2024)
  • 11.4.9 静态成员 [class.static]
  • C++20 标准 (ISO/IEC 14882:2020)
  • 11.4.8 静态成员 [class.static]
  • C++17 标准 (ISO/IEC 14882:2017)
  • 12.2.3 静态成员 [class.static]
  • C++14 标准 (ISO/IEC 14882:2014)
  • 9.4 静态成员 [class.static]
  • C++11 标准 (ISO/IEC 14882:2011)
  • 9.4 静态成员 [class.static]
  • C++98 标准 (ISO/IEC 14882:1998)
  • 9.4 静态成员 [class.static]

[编辑] 另请参阅