~A() { cout << "Hello from A\n"; }
};
class B : virtual public A
{
public:
~B() override { cout << "Greeting from B\n"; }
};
class D : public B
{
public:
~D() override { cout << "Greeting from D\n"; }
};
int main()
{
A* d = new D;
delete d;
d = nullptr;
return 0;
}
как то можно сделать так, чтобы деструктор базового класса не унаследовался виртуально для деструктора класса D?
можно: не наследуйте D от базового класса
ключевое слово НЕ виртуально, то есть мне нужно обычное наследование именно для D
Деструктор базового класса и так наследуется невиртуально.
(прочиал UPD) вы хотите чтобы у объекта с динамическим типом D НЕ вызывался деструктор от типа D?
хорошо, давайте другой пример с Show #include <iostream> using std::cout; using std::cin; using std::endl; class A { public: virtual void Show() { cout << "Hello from A\n"; } }; class B : public A { public: void Show() override { cout << "Greeting from B\n"; } }; class D : public B { public: void Show() override { cout << "Greeting from D\n"; } }; int main() { A* d = new D; d->Show(); return 0; }
И ? Только быстрее, а то я спать уйду
хочу чтобы вызвался Show из B
Что вызывалось ?
так, всё, пора спрашивать то, что я не люблю спрашивать: ЗАЧЕМ?
Нет проблем! class D : public B { public: void Show() override { B::Show(); } };
здесь метод Show виртуально унаследовался?
d->B::Show()?
хочу понаписать наследования с virtual'ами, но чтобы работало как без virtual'ов и без наследования
Такого не бывает. Методы наслеюуются или нет, и бывают виртуальными или нет
тогда надо не делать virtual и не наследоваться !
ну вот здесь он виртуально унаследовался, верно? у нас же есть указатель базового класса через который мы вызываем метод D
нет! я хочу с virtual'ами! 😂
Да, он в базовом объявлен виртуальным, будет везде виртуальным
Я не очень понимаю в виртуальном этом всем, но думаю, для того что ты хочешь надо просто в классе D не определять метод show. (но я не уверен)
Нельзя метод унаследовать виртуально или нет. Методы просто наследуются или нет, и могут быть виртуальными или нет.
тут явно заявка на пропозал на киллерфичу для C++29
Он ВЫЗЫВАЕТСЯ виртуально, а не наследуется.
Не совсем понял твои слова "метод наследуется ИЛИ нет". Я всегда думал, что если в базовом классе есть какой то метод, то в производном он будет по любому. Он всегда наследуется. Другое дело, что если он виртуальный, то ты можешь его переопределить в производном. Или все таки можно как то сделать так, чтоб метод базового вообще по попадал в состав производного? Мне кажется так нельзя
Не всегда, но в общем да.
ну вот есть class A { public: virtual Show(); } здесь этот метод Show будет ко всей цепочке унаследованных классов являться virtual?
Да. По другому не бывает
Понял. Но тогда его можно будет вызвать только через указатель на производный (через базовый нельзя) верно я понимаю?
ещё раз переспрошу для уверенности, то есть class A { public: virtual void Show(); }; class B : public A { public: void Show(); }; class C : public B { public: void Show(): }; здесь метод Show в классе C никак обычно не унаследовать UPD: чтобы при вызове A* c = new C; c.Show(); вызвался метод класса B, но не C. Просто есть цепочка A->B->C, если метод Show класса С можно как то унаследовать обычно, то тогда по логике должно вызваться Show метода B )))
Ну и приватные функции функционально (не технически) не наследуются по понятным причинам.
наследуются
Только технически. Использовать это никак не получится (по крайней мере без очень грязных хаков).
апдейтнул
Ну тебе компилятор при вызове будет говорить, что метод недоступен. Вот если его ПЕРЕГРУЗИТЬ в наследнике, он скроется.
Я писал выше. Переопределить в C метод Show() и вызвать в нём метод класса B (B::Show). НО c деструкторами такой финт не прокатит, 0) деструктор всегда есть и 1) он всегда будет вызван, 2) и потом будет вызван деструктор базового класса.
https://en.cppreference.com/w/cpp/memory/memory_resource (обратите внимание на приватные виртуалы)
Я знаю эту шляпу, но не одобряю. Они должны быть protected.
не, не должны, по исходной задумке их только база из невиртуального интерфейса дёргает
да, но только, если будет вызван через свой же указатель, а не через базовый. Потому что если через базовый, то только базовый деструктор и вызовется
Все так: как и для любого другого невиртуального метода. В отличие от них, впрочем, деструктор производного класса, в случае если базовый объявлен виртуальным, не заменит, а дополнит порядок разрушения объекта. Т.е.: struct B { virtual void f ( ); virtual ~B ( ); }; struct D: B { void f ( ) override; ~D ( ) override; }; int main ( ) { B* b{new D}; b->f() /* #1 */; delete b /* #2 */; } В #1 вызовется D::f(), но в #2 вызовется D::~D(), после чего B::~B().
что это за конструкция {new D}?
это да, а если ну будет виртуального наследования, то вызовется в этом случае только деструктор структуры B
Скорее b{}: это один из синтаксисов инициализации. В разных ситуациях (не)возможно использование в этих целях =, () или {} (как здесь). new D - выражение, создающее объект типа D с dynamic-storage-duration (объект, управление временем жизни которого осуществляется вручную и может производиться во время выполнения).
Если точнее, в этом случае будет неопределенное поведение (программа содержит недиагностируемую фатальную ошибку, последствия (даже неизбежного достижения в будущем которой) которой формально непредсказуемы).
у меня твой код не комплится)
Скорее всего потому, что под "не компилится" Вы понимаете "не компонуется": он и не может, поскольку определения для всех используемых функций в примере отсутствуют (они для него не нужны). Если хотите его собрать - замените все точки с запятыми в пределах определений структур на пары фигурных скобок.
а, я этого и не заметил, спвсибо
а с чего вы взяли, что это компоновка а не компиляция? я так почитал, что такое компоновка и как для себя понял, компилятор сначала преобразует всё в машинный код, затем в обьекты, а компоновкщик обьединяет это всё
Компилятор работает в пределах контекста единицы трансляции. Он как раз свою работу способен выполнять и без доступа к определениям функций в том примере.
Ребят, не могли бы Вы поделиться источниками по которым Вы изучали ООП? Всё что я видел либо поверхностное, либо не разбирает подобных махинаций
Непосредственно к ООП это отношения не имеет; это про работу языка. Помимо каких-то преимущественно базовых представлений, конкретно я свои отсюда и отсюда получал. Первое - справочник по языку, второе - актуальный черновик спецификация языка. Насколько такой подход можно рекомендовать - не подскажу.
uniform инициализация адресом, который возвращает оператор new.
а в чем её прикол, или это просто как фишка?
Как по мне, это универсальный способ инициализации и присваивания переменных, массивов и объектов.
Да разбирает. Просто надо вдумываться. В лбом учебнике по с++ это есть, Липпман например, или Детей Детей.
Ты не можешь проигнорировать и обойти деструктор базового класса. Он все равно будет выполнен.
Обсуждают сегодня