Namespaces
Variants

static members

From ru.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 member-declaration), но может появляться в любом месте последовательности спецификаторов.

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

Объяснение

Статические члены класса не связаны с объектами класса: они являются независимыми переменными со статической или поточной (начиная с 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]

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