Вложенные классы
Объявление класса/структуры или объединения может находиться внутри другого класса. Такое объявление объявляет вложенный класс.
Пояснение
Имя вложенного класса существует в области видимости охватывающего класса, а поиск имени из функции-члена вложенного класса обращается к области видимости охватывающего класса после проверки области видимости вложенного класса. Как и любой член охватывающего класса, вложенный класс имеет доступ ко всем именам (private, protected и т. д.), к которым имеет доступ охватывающий класс, но в остальном он независим и не имеет специального доступа к указателю this охватывающего класса. В объявлениях вложенного класса можно использовать любые члены охватывающего класса, следуя обычным правилам использования нестатических членов.
int x, y; // globals
class enclose // enclosing class
{
// note: private members
int x;
static int s;
public:
struct inner // nested class
{
void f(int i)
{
x = i; // Error: can't write to non-static enclose::x without instance
int a = sizeof x; // Error until C++11,
// OK in C++11: operand of sizeof is unevaluated,
// this use of the non-static enclose::x is allowed.
s = i; // OK: can assign to the static enclose::s
::x = i; // OK: can assign to global x
y = i; // OK: can assign to global y
}
void g(enclose* p, int i)
{
p->x = i; // OK: assign to enclose::x
}
};
};
Функции-друзья, определённые внутри вложенного класса, не имеют специального доступа к членам охватывающего класса, даже если поиск из тела функции-члена, определённой внутри вложенного класса, может обнаружить закрытые члены охватывающего класса.
Определения членов вложенного класса вне класса размещаются в пространстве имён охватывающего класса:
struct enclose
{
struct inner
{
static int x;
void f(int i);
};
};
int enclose::inner::x = 1; // definition
void enclose::inner::f(int i) {} // definition
Вложенные классы можно предварительно объявить, а затем определить — либо в теле того же охватывающего класса, либо за его пределами:
class enclose
{
class nested1; // forward declaration
class nested2; // forward declaration
class nested1 {}; // definition of nested class
};
class enclose::nested2 {}; // definition of nested class
На объявления вложенных классов распространяются спецификаторы доступа к членам: закрытый класс-член нельзя именовать за пределами области видимости охватывающего класса, хотя объектами такого класса можно манипулировать:
class enclose
{
struct nested // private member
{
void g() {}
};
public:
static nested f() { return nested{}; }
};
int main()
{
//enclose::nested n1 = enclose::f(); // error: 'nested' is private
enclose::f().g(); // OK: does not name 'nested'
auto n2 = enclose::f(); // OK: does not name 'nested'
n2.g();
}
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение согласно опубликованной версии | Правильное поведение |
|---|---|---|---|
| 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]
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/nested_classes