Вложенные классы
Объявление класса/структуры или объединения может содержать внутри другой класс. Это и будет Вложенный класс.
[править]Объяснение
Имя вложенного класса существует в области видимости окружающего класса и поиск имён из метода вложенного класса посетит область видимости окружающего класса, если в своём ничего не найдёт. Как и любой элемент окружающего класса, вложенный класс имеет доступ ко всем именам (приватным, защищённым и так далее) к которым окружающий класс имеет доступ, но так или иначе является независимым и не имеет специального доступа к указателю this окружающего класса.
Объявления во вложенном классе могут использовать только имена типов, статические элементы и перечислители из окружающего класса. | (до C++11) |
Объявления во вложенном классе могут использовать любые элементы окружающего класса, следуя обычным правилам использования для нестатических свойств. | (начиная с C++11) |
int x,y;// глобальные переменныеclass enclose // окружающий класс{// заметьте: закрытые элементыint x;staticint 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 {staticint 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]