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