Вложенные классы в C++ контринтуитивны (воняют)

Вот сидишь ты, никого не трогаешь, никому не мешаешь, пишешь функцию у класса:

class A { int x; void func() { x = 3; } };

и всё хорошо, всё компилируется, бабочки летают, радуга цветёт, птички песенку поют.

Пишешь ты метод у вложенного класса

class A { int x; class B { void func() { x = 3; } }; };

И тут внезапно сгущаются тучи, льёт дождь, тебя обдаёт грязью проезжающий по дороге засранный жигуль, спидозный голубь срёт тебе прямо на голову, ты весь в дерьме, компилятор тебе говорит
INVALID USE OF NON-STATIC DATA MEMBER ИЛИ ПОШЁЛ НАХУЙ ЕСЛИ НЕ ПОНЯЛ
Оказывается, что C++ это такой вот прекрасный язык, в котором экземпляр вложенного класса может существовать без внешнего класса, просто вот в вакууме, беспризорник без родителей спиздил деньги в раздевалке и бродит по улице нахуй ворует кабачки:

class A { public: int x; class B { int y; }; }; int main() { A::B E; }

Это скомпилируется. Экземпляр E класса B знать не знает ни про какой объемлющий класс A и что у него есть какое-то там целочисленное поле x.
Как следствие такого подхода, при входе в тело вложенного класса компилятор "забывает" про поля объемлющего класса.
Конечно, компилятору можно напомнить о существовании экземпляра объемлющего класса:

class A { int x; class B { void func(A &dolboeb) { dolboeb.x = 3; } }; };

Но тогда при вызове func() нам придётся везде каждый раз передавать в func() экземпляр объемлющего класса.

Удобно, не правда ли?
Я для себя пришёл к весьма тоскливому выводу, что проще смириться с тем, что вложенные классы в C++ нифига не вложенные "на самом деле" и что, возможно, имеет смысл вынести тело "вложенного" класса отдельно, как-то так:

#include <vector> class submissive_B; class A { public: int x = 0; std::vector <submissive_B> kogorta_pidarasov; }; class submissive_B { void func(A &dungeon_master) { dungeon_master.x = 1; } }; int main() { }

Или всё же писать вложенные классы, но методы к ним писать в объемлющем классе.
Очень грустно. И мне непонятно, почему в C++ так. Наверное, кому-то понятно, но мне непонятно.

1414
33
22
11
11
90 комментариев

Сделай вложенный класс private, а не public, и тогда
Это скомпилируется.компилироваться это не будет.

Экземпляр E класса B знать не знает ни про какой объемлющий класс A и что у него есть какое-то там целочисленное поле xА должен? Если он знает о его существовании, то ты где-то накосячил с проектированием и нарушаешь принципы ООП

16
Ответить

Классы - абстракция, модель, описывающая какую-то сущность. Если в твоей абстракции модель знает о том, что она часть чего-то большего и она обязана ей быть - передавай в конструкторе ссылку на это общее. И пусть она обращается строго по указателю к своему "владельцу".

8
Ответить

я бы хотел, чтоб знал. Вон там ява программист ответил выше, что в Яве знает.

Ответить

C++ по умолчанию поля класса считается все private. А вот поля структуры - public. Там не нужно ему писать private в данном случае.

Ответить

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

6
Ответить

весь пост это и есть нытьё о том, как же плохо, что он не знает, как в той же Яве

1
Ответить

Потому что то что ты делаешь, это обьявление вложенного класа в его неймспейсе, а не экземпляр. В данном случае, тебе нужен экземпляр. Что логично, сьхерали вложенный класс должен знать, в кого он вложен?

Агрегация или композиция не подразумивает, что экземпляр будет знать, где он находится.

Передай овнера через конструктор, коль уж надо.

5
Ответить