Nested classes
Une déclaration d'une classe/structure ou d'une union peut apparaître dans une autre classe. Une telle déclaration définit une classe imbriquée .
Explication
Le nom de la classe imbriquée existe dans la portée de la classe englobante, et la recherche de nom à partir d'une fonction membre d'une classe imbriquée visite la portée de la classe englobante après avoir examiné la portée de la classe imbriquée. Comme tout membre de sa classe englobante, la classe imbriquée a accès à tous les noms (private, protected, etc) auxquels la classe englobante a accès, mais elle est par ailleurs indépendante et n'a pas d'accès spécial au
this
pointer
de la classe englobante. Les déclarations dans une classe imbriquée peuvent utiliser n'importe quel membre de la classe englobante, en suivant les
règles d'utilisation habituelles
pour les membres non statiques.
int x, y; // variables globales class enclose // classe englobante { // note : membres privés int x; static int s; public: struct inner // classe imbriquée { void f(int i) { x = i; // Erreur : impossible d'écrire dans enclose::x non statique sans instance int a = sizeof x; // Erreur jusqu'à C++11, // OK en C++11 : l'opérande de sizeof n'est pas évalué, // cet usage de enclose::x non statique est autorisé. s = i; // OK : peut assigner à enclose::s statique ::x = i; // OK : peut assigner à x global y = i; // OK : peut assigner à y global } void g(enclose* p, int i) { p->x = i; // OK : assigne à enclose::x } }; };
Friend Les fonctions définies dans une classe imbriquée n'ont aucun accès spécial aux membres de la classe englobante, même si la recherche à partir du corps d'une fonction membre définie dans une classe imbriquée peut trouver les membres privés de la classe englobante.
Les définitions hors-classe des membres d'une classe imbriquée apparaissent dans l'espace de noms de la classe englobante :
struct enclose { struct inner { static int x; void f(int i); }; }; int enclose::inner::x = 1; // définition void enclose::inner::f(int i) {} // définition
Les classes imbriquées peuvent être déclarées à l'avance et définies ultérieurement, soit dans le même corps de classe englobante, soit en dehors de celui-ci :
class enclose { class nested1; // déclaration anticipée class nested2; // déclaration anticipée class nested1 {}; // définition de la classe imbriquée }; class enclose::nested2 {}; // définition de la classe imbriquée
Les déclarations de classes imbriquées respectent les spécificateurs d'accès des membres : une classe membre privée ne peut pas être nommée en dehors de la portée de la classe englobante, bien que les objets de cette classe puissent être manipulés :
class enclose { struct nested // membre privé { void g() {} }; public: static nested f() { return nested{}; } }; int main() { //enclose::nested n1 = enclose::f(); // erreur: 'nested' est privé enclose::f().g(); // OK: ne nomme pas 'nested' auto n2 = enclose::f(); // OK: ne nomme pas 'nested' n2.g(); }
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 | Applicable à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 45 | C++98 |
les membres d'une classe imbriquée ne peuvent pas
accéder à la classe englobante et à ses amis |
ils ont les mêmes droits d'accès que
les autres membres de la classe englobante (résout également les problèmes CWG #8 et #10) |
Références
- Norme C++23 (ISO/IEC 14882:2024) :
-
- 11.4.12 Déclarations de classes imbriquées [class.nest]
- Norme C++20 (ISO/IEC 14882:2020) :
-
- 11.4.10 Déclarations de classes imbriquées [class.nest]
- Norme C++17 (ISO/IEC 14882:2017) :
-
- 12.2.5 Déclarations de classes imbriquées [class.nest]
- Norme C++14 (ISO/CEI 14882:2014) :
-
- 9.7 Déclarations de classes imbriquées [class.nest]
- Norme C++11 (ISO/IEC 14882:2011) :
-
- 9.7 Déclarations de classes imbriquées [class.nest]
- Norme C++98 (ISO/CEI 14882:1998) :
-
- 9.7 Déclarations de classes imbriquées [class.nest]