Пространства имён
Варианты
Действия

Вложенные классы

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

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

[править] Объяснение

Имя вложенного класса существует в области видимости окружающего класса и поиск имён из метода вложенного класса посетит область видимости окружающего класса, если в своём ничего не найдёт. Как и любой элемент окружающего класса, вложенный класс имеет доступ ко всем именам (приватным, защищённым и так далее) к которым окружающий класс имеет доступ, но так или иначе является независимым и не имеет специального доступа к указателю this окружающего класса.

Объявления во вложенном классе могут использовать только имена типов, статические элементы и перечислители из окружающего класса. (до C++11)

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

(начиная с C++11)
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; // Ошибка до С++11,
                              // OK в С++11: операнд не оценивается
                              // такое использование нестатического
                              // 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
        }
    };
};

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

Внеклассовые определения элементов вложенного класса содержатся в пространстве имён внешнего класса:

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++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 45 C++98 элементы вложенных классов не могли
иметь доступа к окружающему классу и его друзьям
имеют те-же права доступа, как и
другие элементы окружающего класса
(также решило CWG проблемы №8 и №10)

[править] Ссылки

  • 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]