Виртуальные деструкторы для интерфейсов

Нужны ли интерфейсам виртуальный деструктор или автогенерация? Например, какой из следующих двух фрагментов кода лучше всего, и почему? Обратите внимание, что это класс 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:

Мое второе редактирование просто неверно и дезинформация. Пожалуйста, прочитайте комментарии реальных умных людей для получения дополнительной информации.

Ответ 1

Рассмотрим следующий случай:

   Base *Var = new Derived();
   delete Var;

Вам нужен виртуальный деструктор, иначе, когда вы удалите Var, деструктор производного класса никогда не будет вызван.

Ответ 2

Если вы удаляете объект производного класса с помощью указателя базового класса в С++, результатом является поведение undefined. UB - это то, чего вы действительно хотите избежать, поэтому вы должны дать базовым классам виртуальный деструктор. Чтобы привести цитату из стандарта С++, раздел 5.3.5:

если статический тип операнда отличается от своего динамического типа, статический тип должен быть базовым классом динамический тип операндов и статический тип должен иметь виртуальный деструктор или поведение undefined.

Ответ 3

Вы должны использовать виртуальный деструктор, если вы ожидаете, что люди попытаются удалить объекты производного класса с помощью указателей или ссылок родительского класса. Если это так, то без виртуального деструктора производный класс никогда не будет должным образом разрушен.

Например,

Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;

Без виртуального деструктора в базе, Derived destructor никогда не будет вызван, и поэтому важные вещи никогда не произойдут.

Ответ 4

Ответ в основном на редактирование:

Никто не может сказать вам, что произойдет, потому что результат "undefined поведение". Когда вы удаляете производный класс с помощью указателя на базу, которая не имеет виртуального деструктора, реализация может разрываться любым количеством способов.

Ответ 5

В общем случае деструктор должен быть либо (1) общедоступным и виртуальным, либо (2) защищенным и не виртуальным.

Предполагая, что вы никогда не ожидаете, что кто-либо удалит экземпляр класса с помощью указателя интерфейса, защищенный не виртуальный деструктор будет на 100% безопасным.

Если кто-то пытается удалить указатель интерфейса в случае (2), он получит ошибку времени компиляции.

Ответ 6

Нет... виртуальные деструкторы не генерируются автоматически. Вы должны объявить их явно в своем базовом классе. Но вам не нужно объявлять ваши деструкторы виртуальными для дочерних классов Base. Это делается компилятором. Компилятор также удостоверится, что деструкторы вызываются в обратном порядке построения (от производной до базы).

public class Base 
{
 //...
}

public class Derived
{
   int i = 0;
   //...
}

//...

Base* b = new Derived();

Если у вас не было виртуального деструктора

delete b;

приведет к утечкам памяти (не менее 4 байтов для целочисленного поля), поскольку это приведет к уничтожению только Base, а не Derived. Виртуальность гарантирует, что производные классы также будут уничтожены. Вам не нужно объявлять виртуальный конструктор в Derived, это будет выведено компилятором, если вы объявили виртуальный деструктор в Base.