Nested classes
Объявление класса/структуры или объединения может находиться внутри другого класса. Такое объявление объявляет вложенный класс .
Объяснение
Имя вложенного класса существует в области видимости объемлющего класса, и поиск имени из функции-члена вложенного класса просматривает область видимости объемлющего класса после проверки области видимости вложенного класса. Как и любой член своего объемлющего класса, вложенный класс имеет доступ ко всем именам (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]