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

Объявление класса/структуры или объединения может находиться внутри другого класса. Такое объявление объявляет вложенный класс .

Объяснение

Имя вложенного класса существует в области видимости объемлющего класса, и поиск имени из функции-члена вложенного класса просматривает область видимости объемлющего класса после проверки области видимости вложенного класса. Как и любой член своего объемлющего класса, вложенный класс имеет доступ ко всем именам (private, protected и т.д.), к которым имеет доступ объемлющий класс, но в остальном он независим и не имеет специального доступа к this pointer объемлющего класса. Объявления во вложенном классе могут использовать любые члены объемлющего класса, следуя обычным правилам использования для нестатических членов.

int x, y; // глобальные переменные
class enclose // внешний класс
{
    // примечание: приватные члены
    int x;
    static int s;
public:
    struct inner // вложенный класс
    {
        void f(int i)
        {
            x = i; // Ошибка: нельзя записать в нестатическую enclose::x без экземпляра
            int a = sizeof x; // Ошибка до C++11,
                              // OK в C++11: операнд sizeof не вычисляется,
                              // такое использование нестатической enclose::x разрешено.
            s = i;   // OK: можно присвоить статической enclose::s
            ::x = i; // OK: можно присвоить глобальной x
            y = i;   // OK: можно присвоить глобальной y
        }
        void g(enclose* p, int i)
        {
            p->x = i; // OK: присвоить enclose::x
        }
    };
};

Friend функции, определенные внутри вложенного класса, не имеют специального доступа к членам объемлющего класса, даже если поиск из тела функции-члена, определенной внутри вложенного класса, может находить приватные члены объемлющего класса.

Определения членов вложенного класса вне класса находятся в пространстве имен объемлющего класса:

struct enclose
{
    struct inner
    {
        static int x;
        void f(int i);
    };
};
int enclose::inner::x = 1;       // определение
void enclose::inner::f(int i) {} // определение

Вложенные классы могут быть предварительно объявлены и затем определены, либо в том же теле объемлющего класса, либо вне его:

class enclose
{
    class nested1;    // предварительное объявление
    class nested2;    // предварительное объявление
    class nested1 {}; // определение вложенного класса
};
class enclose::nested2 {}; // определение вложенного класса

Объявления вложенных классов подчиняются спецификаторам доступа членов , закрытый класс-член не может быть упомянут вне области объемлющего класса, хотя объекты этого класса могут использоваться:

class enclose
{
    struct nested // закрытый член
    {
        void g() {}
    };
public:
    static nested f() { return nested{}; }
};
int main()
{
    //enclose::nested n1 = enclose::f(); // ошибка: 'nested' является закрытым
    enclose::f().g();       // OK: не использует имя 'nested'
    auto n2 = enclose::f(); // OK: не использует имя 'nested'
    n2.g();
}

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 45 C++98 члены вложенного класса не могут
обращаться к объемлющему классу и его друзьям
они имеют те же права доступа, что и
другие члены объемлющего класса
(также решает проблемы CWG #8 и #10)

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 11.4.12 Объявления вложенных классов [class.nest]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 11.4.10 Объявления вложенных классов [class.nest]
  • Стандарт C++17 (ISO/IEC 14882:2017):
  • 12.2.5 Объявления вложенных классов [class.nest]
  • Стандарт C++14 (ISO/IEC 14882:2014):
  • 9.7 Объявления вложенных классов [class.nest]
  • Стандарт C++11 (ISO/IEC 14882:2011):
  • 9.7 Объявления вложенных классов [class.nest]
  • Стандарт C++98 (ISO/IEC 14882:1998):
  • 9.7 Объявления вложенных классов [class.nest]