static
members
À l'intérieur d'une définition de classe, le mot-clé static déclare des membres qui ne sont pas liés aux instances de classe.
En dehors d'une définition de classe, cela a une signification différente : voir storage duration .
Table des matières |
Syntaxe
Une déclaration pour un membre statique est une déclaration de membre dont les spécificateurs de déclaration contiennent le mot-clé static . Le mot-clé static apparaît généralement avant les autres spécificateurs (c'est pourquoi la syntaxe est souvent décrite informellement comme static data-member ou static member-function ), mais peut apparaître n'importe où dans la séquence de spécificateurs.
Le nom de tout membre de données statique et fonction membre statique doit être différent du nom de la classe qui les contient.
Explication
Les membres statiques d'une classe ne sont pas associés aux objets de la classe : ce sont des variables indépendantes avec une durée de stockage statique (depuis C++11) ou thread ou des fonctions régulières.
Le mot-clé static est uniquement utilisé avec la déclaration d'un membre statique, à l'intérieur de la définition de la classe, mais pas avec la définition de ce membre statique :
class X { static int n; }; // déclaration (utilise 'static') int X::n = 1; // définition (n'utilise pas 'static')
La déclaration à l'intérieur du corps de la classe n'est pas une définition et peut déclarer le membre comme étant de type incomplet (autre que void ), y compris le type dans lequel le membre est déclaré :
struct Foo; struct S { static int a[]; // déclaration, type incomplet static Foo x; // déclaration, type incomplet static S s; // déclaration, type incomplet (dans sa propre définition) }; int S::a[10]; // définition, type complet struct Foo {}; Foo S::x; // définition, type complet S S::s; // définition, type complet
|
Cependant, si la déclaration utilise constexpr ou inline (depuis C++17) le membre doit être déclaré avec un type complet. |
(depuis C++11) |
Pour faire référence à un membre statique
m
de la classe
T
, deux formes peuvent être utilisées : le nom qualifié
T::m
ou l'expression d'accès membre
E.m
ou
E->m
, où
E
est une expression qui s'évalue respectivement en
T
ou
T*
. Lorsqu'on se trouve dans la même portée de classe, la qualification n'est pas nécessaire :
struct X { static void f(); // déclaration static int n; // déclaration }; X g() { return X(); } // une fonction retournant X void f() { X::f(); // X::f est un nom qualifié de fonction membre statique g().f(); // g().f est une expression d'accès membre se référant à une fonction membre statique } int X::n = 7; // définition void X::f() // définition { n = 1; // X::n est accessible simplement comme n dans cette portée }
Les membres statiques respectent les règles d'accès aux membres de classe (private, protected, public) .
Fonctions membres statiques
Les fonctions membres statiques ne sont associées à aucun objet. Lorsqu'elles sont appelées, elles n'ont pas de this pointeur.
Les fonctions membres statiques ne peuvent pas être virtual , const , volatile , ou ref-qualified .
L'adresse d'une fonction membre statique peut être stockée dans un pointeur vers fonction ordinaire, mais pas dans un pointeur vers fonction membre .
Membres de données statiques
Les membres de données statiques ne sont associés à aucun objet. Ils existent même si aucun objet de la classe n'a été défini. Il n'existe qu'une seule instance du membre de données statique dans l'ensemble du programme avec une durée de stockage statique , sauf si le mot-clé thread_local est utilisé, auquel cas il existe un tel objet par thread avec une durée de stockage de thread (depuis C++11) .
Les membres de données statiques ne peuvent pas être mutable .
Les membres de données statiques d'une classe dans la portée d'un espace de noms ont une liaison externe si la classe elle-même a une liaison externe (n'est pas membre d'un espace de noms sans nom ). Les classes locales (classes définies à l'intérieur de fonctions) et les classes sans nom, y compris les classes membres de classes sans nom, ne peuvent pas avoir de membres de données statiques.
|
Un membre de données statique peut être déclaré inline . Un membre de données statique inline peut être défini dans la définition de la classe et peut spécifier un initialiseur. Il ne nécessite pas de définition hors-classe : 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 }; |
(depuis C++17) |
Membres statiques constants
Si un membre de données statique de type intégral ou énumération est déclaré const (et non volatile ), il peut être initialisé avec un initialiseur dans lequel chaque expression est une expression constante , directement à l'intérieur de la définition de la classe :
struct X { const static int n = 1; const static int m{2}; // depuis C++11 const static int k; }; const int X::k = 3;
|
Si un membre de données statique de LiteralType est déclaré constexpr , il doit être initialisé avec un initialiseur dans lequel chaque expression est une expression constante, directement dans la définition de la classe : 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 }; |
(depuis C++11) |
Si un membre de données statique const non inline (depuis C++17) ou un membre de données statique constexpr (depuis C++11) (jusqu'à C++17) est ODR-use , une définition au niveau de la portée de l'espace de noms est toujours requise, mais elle ne peut pas avoir d'initialiseur.
|
Un membre de données constexpr statique est implicitement inline et n'a pas besoin d'être redéclaré au niveau de la portée du namespace. Cette redéclaration sans initialiseur (auparavant requise) est toujours autorisée, mais est dépréciée. |
(depuis C++17) |
struct X { static const int n = 1; static constexpr int m = 4; }; const int *p = &X::n, *q = &X::m; // X::n et X::m sont ODR-utilisés const int X::n; // … donc une définition est nécessaire constexpr int X::m; // … (sauf pour X::m en C++17)
Mots-clés
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 194 | C++98 | les noms de fonctions membres (statiques) peuvent être identiques au nom de la classe |
restriction de nommage ajoutée (incluant
les fonctions membres non statiques ) |
Références
- Norme C++23 (ISO/CEI 14882:2024) :
-
- 11.4.9 Membres statiques [class.static]
- Norme C++20 (ISO/CEI 14882:2020) :
-
- 11.4.8 Membres statiques [class.static]
- Norme C++17 (ISO/IEC 14882:2017) :
-
- 12.2.3 Membres statiques [class.static]
- Norme C++14 (ISO/CEI 14882:2014) :
-
- 9.4 Membres statiques [class.static]
- Norme C++11 (ISO/IEC 14882:2011) :
-
- 9.4 Membres statiques [class.static]
- Norme C++98 (ISO/CEI 14882:1998) :
-
- 9.4 Membres statiques [class.static]