Namespaces
Variants

static members

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous

Внутри определения класса ключевое слово static объявляет члены, которые не привязаны к экземплярам класса.

Вне определения класса это имеет другое значение: см. storage duration .

Содержание

Синтаксис

Объявление для статического члена является объявлением члена , спецификаторы объявления которого содержат ключевое слово static . Ключевое слово static обычно появляется перед другими спецификаторами (поэтому синтаксис часто неформально описывается как static data-member или static member-function ), но может появляться в любом месте последовательности спецификаторов.

Имя любого статического члена данных и статической функции-члена должно отличаться от имени содержащего класса.

Объяснение

Статические члены класса не связаны с объектами класса: они являются независимыми переменными со статической или поточной (начиная с C++11) продолжительностью хранения или обычными функциями.

Ключевое слово static используется только при объявлении статического члена внутри определения класса, но не при определении этого статического члена:

class X { static int n; }; // объявление (использует 'static')
int X::n = 1;              // определение (не использует 'static')

Объявление внутри тела класса не является определением и может объявлять член как неполный тип (кроме void ), включая тип, в котором объявлен член:

struct Foo;
struct S
{
    static int a[]; // объявление, неполный тип
    static Foo x;   // объявление, неполный тип
    static S s;     // объявление, неполный тип (внутри собственного определения)
};
int S::a[10]; // определение, полный тип
struct Foo {};
Foo S::x;     // определение, полный тип
S S::s;       // определение, полный тип

Однако, если объявление использует constexpr или inline (начиная с C++17) спецификатор, член должен быть объявлен с полным типом.

(начиная с C++11)

Для обращения к статическому члену m класса T могут использоваться две формы: квалифицированное имя T::m или выражение доступа к члену E.m или E->m , где E является выражением, которое вычисляется в T или T* соответственно. Когда обращение происходит в той же области видимости класса, квалификация не требуется:

struct X
{
    static void f(); // объявление
    static int n;    // объявление
};
X g() { return X(); } // некоторая функция, возвращающая X
void f()
{
    X::f();  // X::f - квалифицированное имя статической функции-члена
    g().f(); // g().f - выражение доступа к члену, ссылающееся на статическую функцию-член
}
int X::n = 7; // определение
void X::f() // определение
{
    n = 1; // X::n доступен как просто n в этой области видимости
}

Статические члены подчиняются правилам доступа к членам класса (private, protected, public) .

Статические функции-члены

Статические функции-члены не связаны с каким-либо объектом. При вызове у них отсутствует this указатель.

Статические функции-члены не могут быть virtual , const , volatile , или ref-qualified .

Адрес статической функции-члена может быть сохранён в обычном указателе на функцию , но не в указателе на функцию-член .

Статические члены данных

Статические члены данных не связаны с каким-либо объектом. Они существуют, даже если не определены объекты класса. В программе существует только один экземпляр статического члена данных со статической продолжительностью хранения , если не используется ключевое слово 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}; // начиная с 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)

Если константный не-inline (since C++17) статический член данных или constexpr статический член данных (since C++11) (until C++17) подвергается ODR-использованию , определение в области видимости пространства имён всё ещё требуется, но оно не может иметь инициализатора.

Статический элемент данных constexpr является неявно inline и не требует повторного объявления в области видимости пространства имен. Такое повторное объявление без инициализатора (ранее требовавшееся) всё ещё разрешено, но считается устаревшим.

(since C++17)
struct X
{
    static const int n = 1;
    static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n и X::m являются ODR-используемыми
const int X::n;             // … поэтому определение необходимо
constexpr int X::m;         // … (кроме X::m в C++17)

Ключевые слова

static

Отчеты о дефектах

Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 194 C++98 имена (статических) функций-членов могут совпадать с именем класса добавлено ограничение на именование (включая
нестатические функции-члены )

Ссылки

  • Стандарт 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]

Смотрите также