Зачем в C++ объявлять деструктор виртуальным
Что проверяют
Понимаете ли вы механику вызова деструктора через указатель на базовый класс. Вопрос короткий, но по ответу сразу видно, работали ли вы с иерархиями.
Как отвечать
Если объект производного класса удаляют через указатель на базовый, а деструктор базового не виртуальный, стандарт объявляет поведение неопределённым. На практике вызовется только деструктор базового класса: поле производного не освободится, память утечёт.
struct Base { virtual ~Base() = default; }; // так правильно
struct Derived : Base { std::vector<int> data; };
Base* p = new Derived;
delete p; // без virtual деструктор Derived не вызоветсяВиртуальный деструктор кладёт запись в таблицу виртуальных функций, и delete находит нужную реализацию во время выполнения.
Правило простое: класс предназначен для наследования и удаления через базовый указатель, значит деструктор либо public и virtual, либо protected и не virtual (тогда через базовый указатель удалять нельзя по построению).
Цена: у класса появляется указатель на таблицу, объект растёт на размер указателя, и класс перестаёт быть тривиально копируемым. Для мелких типов без наследования это лишнее.
Где спотыкаются
Говорят «на всякий случай всегда virtual». У структуры-значения из двух чисел это лишние восемь байт на объект и потеря тривиальности.
Не знают, что проблема ровно в удалении через базовый указатель: при удалении через Derived* всё вызовется правильно и без virtual.
Забывают про unique_ptr<Base>: он делает тот же delete и ломается так же.
Не могут назвать альтернативу: shared_ptr запоминает деструктор при создании, поэтому с ним объект удалится корректно даже без виртуального деструктора.