static Member
Innerhalb einer Klassendefinition deklariert das Schlüsselwort static Member, die nicht an Klasseninstanzen gebunden sind.
Außerhalb einer Klassendefinition hat es eine andere Bedeutung: siehe Speicherdauer.
Inhalt |
[bearbeiten] Syntax
Eine Deklaration für einen statischen Member ist eine Member-Deklaration, deren Deklarationsspezifizierer das Schlüsselwort static enthalten. Das Schlüsselwort static erscheint normalerweise vor anderen Spezifizierern (weshalb die Syntax oft informell als static Datenmember oder static Memberfunktion beschrieben wird), kann aber überall in der Spezifizierersequenz erscheinen.
Der Name jedes statischen Datenmembers und jeder statischen Memberfunktion muss sich vom Namen der enthaltenden Klasse unterscheiden.
[bearbeiten] Erklärung
Statische Member einer Klasse sind nicht mit Objekten der Klasse verbunden: Sie sind unabhängige Variablen mit statischer oder Thread(seit C++11) Speicherdauer oder normale Funktionen.
Das Schlüsselwort static wird nur mit der Deklaration eines statischen Members, innerhalb der Klassendefinition, aber nicht mit der Definition dieses statischen Members verwendet.
class X { static int n; }; // declaration (uses 'static') int X::n = 1; // definition (does not use 'static')
Die Deklaration innerhalb des Klassenkörpers ist keine Definition und darf den Member als vom unvollständigen Typ deklarieren (außer void), einschließlich des Typs, in dem der Member deklariert wird.
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
|
Wenn die Deklaration jedoch die Spezifizierer constexpr oder inline(seit C++17) verwendet, muss der Member als vollständiger Typ deklariert werden. |
(seit C++11) |
Um auf einen statischen Member m der Klasse T zuzugreifen, können zwei Formen verwendet werden: qualifizierter Name T::m oder ein Member-Zugriffs-Ausdruck E.m oder E->m, wobei E ein Ausdruck ist, der zu T bzw. T* evaluiert. Wenn sich im selben Klassengültigkeitsbereich, ist die Qualifizierung unnötig.
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 }
Statische Member unterliegen den Regeln für den Zugriff auf Klassenmember (private, protected, public).
[bearbeiten] Statische Member-Funktionen
Statische Member-Funktionen sind nicht mit einem Objekt verbunden. Beim Aufruf haben sie keinen this-Zeiger.
Statische Member-Funktionen können nicht virtual, const, volatile oder Referenz-qualifiziert sein.
Die Adresse einer statischen Member-Funktion kann in einem regulären Funktionszeiger gespeichert werden, aber nicht in einem Member-Funktionszeiger.
[bearbeiten] Statische Datenmember
Statische Datenmember sind nicht mit einem Objekt verbunden. Sie existieren, auch wenn keine Objekte der Klasse definiert wurden. Es gibt nur eine Instanz des statischen Datenmembers im gesamten Programm mit statischer Speicherdauer, es sei denn, das Schlüsselwort thread_local wird verwendet, in diesem Fall gibt es ein solches Objekt pro Thread mit Thread-Speicherdauer(seit C++11).
Statische Datenmember können nicht mutable sein.
Statische Datenmember einer Klasse im Namespace-Gültigkeitsbereich haben eine externe Bindung, wenn die Klasse selbst eine externe Bindung hat (kein Member eines namenlosen Namespace). Lokale Klassen (innerhalb von Funktionen definierte Klassen) und namenlose Klassen, einschließlich Member-Klassen von namenlosen Klassen, können keine statischen Datenmember haben.
|
Ein statischer Datenmember kann inline deklariert werden. Ein Inline-statischer Datenmember kann in der Klassendefinition definiert und mit einem Initialisierer versehen werden. Er benötigt keine Definition außerhalb der Klasse. 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 }; |
(seit C++17) |
[bearbeiten] Konstante statische Member
Wenn ein statischer Datenmember vom ganzzahligen oder Aufzählungstyp als const (und nicht als volatile) deklariert wird, kann er mit einem Initialisierer initialisiert werden, bei dem jeder Ausdruck ein konstanter Ausdruck ist, direkt innerhalb der Klassendefinition.
struct X { const static int n = 1; const static int m{2}; // since C++11 const static int k; }; const int X::k = 3;
|
Wenn ein statischer Datenmember vom LiteralType als constexpr deklariert wird, muss er mit einem Initialisierer initialisiert werden, bei dem jeder Ausdruck ein konstanter Ausdruck ist, direkt innerhalb der Klassendefinition. 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 }; |
(seit C++11) |
Wenn ein const nicht-inline(seit C++17) statischer Datenmember oder ein constexpr statischer Datenmember(seit C++11)(bis C++17) einer ODR-Nutzung unterliegt, ist eine Definition im Namespace-Gültigkeitsbereich immer noch erforderlich, aber sie kann keinen Initialisierer haben.
|
Ein constexpr statischer Datenmember ist implizit inline und muss nicht im Namespace-Gültigkeitsbereich neu deklariert werden. Diese Neudeklaration ohne Initialisierer (früher erforderlich) ist immer noch zulässig, aber veraltet. |
(seit 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)
[bearbeiten] Schlüsselwörter
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 194 | C++98 | (statische) Member-Funktionsnamen können identisch mit dem Klassennamen sein | Namensbeschränkung hinzugefügt (einschließlich nicht-statische Member-Funktionen) |
[bearbeiten] Referenzen
- C++23 Standard (ISO/IEC 14882:2024)
- 11.4.9 Statische Member [class.static]
- C++20 Standard (ISO/IEC 14882:2020)
- 11.4.8 Statische Member [class.static]
- C++17 Standard (ISO/IEC 14882:2017)
- 12.2.3 Statische Member [class.static]
- C++14 Standard (ISO/IEC 14882:2014)
- 9.4 Statische Member [class.static]
- C++11 Standard (ISO/IEC 14882:2011)
- 9.4 Statische Member [class.static]
- C++98 Standard (ISO/IEC 14882:1998)
- 9.4 Statische Member [class.static]