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

Una declaración de una class/struct o union puede aparecer dentro de otra clase. Dicha declaración define una clase anidada .

Explicación

El nombre de la clase anidada existe en el ámbito de la clase envolvente, y la búsqueda de nombres desde una función miembro de una clase anidada visita el ámbito de la clase envolvente después de examinar el ámbito de la clase anidada. Como cualquier miembro de su clase envolvente, la clase anidada tiene acceso a todos los nombres (private, protected, etc) a los que la clase envolvente tiene acceso, pero por lo demás es independiente y no tiene acceso especial al this pointer de la clase envolvente. Las declaraciones en una clase anidada pueden usar cualquier miembro de la clase envolvente, siguiendo las reglas de uso habituales para los miembros no estáticos.

int x, y; // variables globales
class enclose // clase envolvente
{
    // nota: miembros privados
    int x;
    static int s;
public:
    struct inner // clase anidada
    {
        void f(int i)
        {
            x = i; // Error: no se puede escribir en enclose::x no estático sin instancia
            int a = sizeof x; // Error hasta C++11,
                              // OK en C++11: el operando de sizeof no se evalúa,
                              // este uso de enclose::x no estático está permitido.
            s = i;   // OK: se puede asignar al enclose::s estático
            ::x = i; // OK: se puede asignar a la variable global x
            y = i;   // OK: se puede asignar a la variable global y
        }
        void g(enclose* p, int i)
        {
            p->x = i; // OK: asignar a enclose::x
        }
    };
};

Friend Las funciones amigas definidas dentro de una clase anidada no tienen acceso especial a los miembros de la clase envolvente, incluso si la búsqueda desde el cuerpo de una función miembro que está definida dentro de una clase anidada puede encontrar los miembros privados de la clase envolvente.

Las definiciones fuera de la clase de los miembros de una clase anidada aparecen en el espacio de nombres de la clase contenedora:

struct enclose
{
    struct inner
    {
        static int x;
        void f(int i);
    };
};
int enclose::inner::x = 1;       // definición
void enclose::inner::f(int i) {} // definición
He traducido únicamente los comentarios al español: - "definition" → "definición" El código C++ y todas las etiquetas HTML se han mantenido intactos, respetando las instrucciones de no traducir contenido dentro de etiquetas `
`, `` y términos específicos de C++.

Las clases anidadas pueden declararse por adelantado y definirse posteriormente, ya sea dentro del mismo cuerpo de la clase envolvente, o fuera de él:

class enclose
{
    class nested1;    // declaración anticipada
    class nested2;    // declaración anticipada
    class nested1 {}; // definición de clase anidada
};
class enclose::nested2 {}; // definición de clase anidada

Las declaraciones de clases anidadas obedecen los especificadores de acceso de miembros , una clase miembro privada no puede ser nombrada fuera del alcance de la clase envolvente, aunque los objetos de esa clase pueden ser manipulados:

class enclose
{
    struct nested // miembro privado
    {
        void g() {}
    };
public:
    static nested f() { return nested{}; }
};
int main()
{
    //enclose::nested n1 = enclose::f(); // error: 'nested' es privado
    enclose::f().g();       // OK: no nombra 'nested'
    auto n2 = enclose::f(); // OK: no nombra 'nested'
    n2.g();
}

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 45 C++98 los miembros de una clase anidada no pueden
acceder a la clase envolvente y sus amigos
tienen los mismos derechos de acceso que
otros miembros de la clase envolvente
(también resuelve los problemas CWG #8 y #10)

Referencias

  • Estándar C++23 (ISO/IEC 14882:2024):
  • 11.4.12 Declaraciones de clases anidadas [class.nest]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 11.4.10 Declaraciones de clases anidadas [class.nest]
  • Estándar C++17 (ISO/IEC 14882:2017):
  • 12.2.5 Declaraciones de clases anidadas [class.nest]
  • Estándar C++14 (ISO/IEC 14882:2014):
  • 9.7 Declaraciones de clases anidadas [class.nest]
  • Estándar C++11 (ISO/IEC 14882:2011):
  • 9.7 Declaraciones de clases anidadas [class.nest]
  • Estándar C++98 (ISO/IEC 14882:1998):
  • 9.7 Declaraciones de clases anidadas [class.nest]