Namespaces
Variants

Nested classes

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
Special member functions
Templates
Miscellaneous

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]