Ответ 1
Рассмотрим следующий случай:
Base *Var = new Derived();
delete Var;
Вам нужен виртуальный деструктор, иначе, когда вы удалите Var
, деструктор производного класса никогда не будет вызван.
Нужны ли интерфейсам виртуальный деструктор или автогенерация? Например, какой из следующих двух фрагментов кода лучше всего, и почему? Обратите внимание, что это класс WHOLE. Нет других методов, переменных и т.д. В Java-говорить это "интерфейс".
class Base
{
public:
virtual void foo() = 0;
virtual ~Base() {}
};
OR...
class Base
{
public:
virtual void foo() = 0;
~Base() {} // This line can be omitted, but included for clarity.
};
ИЗМЕНИТЬ, ЧТОБЫ "НЕ ЧТО Я ИЩУ ЗА" ОТВЕТЫ:
Каковы последствия каждого маршрута. Пожалуйста, не давайте смутные ответы, такие как "он не будет разрушен должным образом". Пожалуйста, скажите мне, что произойдет. Я немного ботаник сборки.
Изменить 2:
Мне хорошо известно, что "виртуальный" тег означает, что деструктор не будет вызван, если его удалить с помощью указателя на производный, но (я думаю) этот вопрос в конечном итоге сводится к "безопасно ли опустить этот деструктор, ибо действительно ли это тривиально?"
ИЗМЕНИТЬ 3:
Мое второе редактирование просто неверно и дезинформация. Пожалуйста, прочитайте комментарии реальных умных людей для получения дополнительной информации.
Рассмотрим следующий случай:
Base *Var = new Derived();
delete Var;
Вам нужен виртуальный деструктор, иначе, когда вы удалите Var
, деструктор производного класса никогда не будет вызван.
Если вы удаляете объект производного класса с помощью указателя базового класса в С++, результатом является поведение undefined. UB - это то, чего вы действительно хотите избежать, поэтому вы должны дать базовым классам виртуальный деструктор. Чтобы привести цитату из стандарта С++, раздел 5.3.5:
если статический тип операнда отличается от своего динамического типа, статический тип должен быть базовым классом динамический тип операндов и статический тип должен иметь виртуальный деструктор или поведение undefined.
Вы должны использовать виртуальный деструктор, если вы ожидаете, что люди попытаются удалить объекты производного класса с помощью указателей или ссылок родительского класса. Если это так, то без виртуального деструктора производный класс никогда не будет должным образом разрушен.
Например,
Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;
Без виртуального деструктора в базе, Derived destructor никогда не будет вызван, и поэтому важные вещи никогда не произойдут.
Ответ в основном на редактирование:
Никто не может сказать вам, что произойдет, потому что результат "undefined поведение". Когда вы удаляете производный класс с помощью указателя на базу, которая не имеет виртуального деструктора, реализация может разрываться любым количеством способов.
В общем случае деструктор должен быть либо (1) общедоступным и виртуальным, либо (2) защищенным и не виртуальным.
Предполагая, что вы никогда не ожидаете, что кто-либо удалит экземпляр класса с помощью указателя интерфейса, защищенный не виртуальный деструктор будет на 100% безопасным.
Если кто-то пытается удалить указатель интерфейса в случае (2), он получит ошибку времени компиляции.
Нет... виртуальные деструкторы не генерируются автоматически. Вы должны объявить их явно в своем базовом классе. Но вам не нужно объявлять ваши деструкторы виртуальными для дочерних классов Base. Это делается компилятором. Компилятор также удостоверится, что деструкторы вызываются в обратном порядке построения (от производной до базы).
public class Base
{
//...
}
public class Derived
{
int i = 0;
//...
}
//...
Base* b = new Derived();
Если у вас не было виртуального деструктора
delete b;
приведет к утечкам памяти (не менее 4 байтов для целочисленного поля), поскольку это приведет к уничтожению только Base
, а не Derived
. Виртуальность гарантирует, что производные классы также будут уничтожены. Вам не нужно объявлять виртуальный конструктор в Derived
, это будет выведено компилятором, если вы объявили виртуальный деструктор в Base
.