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

Интерфейсам нужен виртуальный деструктор, или действительно ли автоматически сгенерированный прекрасен? Например, какой из следующих двух фрагментов кода является лучшим, и почему? Обратите внимание на то, что это ЦЕЛЫЙ класс. Нет никаких других методов, переменные, и т.д. В Java - говорят, это - "интерфейс".

class Base
{
public:
    virtual void foo() = 0;
    virtual ~Base() {}
};

ИЛИ...

class Base
{
public:
    virtual void foo() = 0;
    ~Base() {} // This line can be omitted, but included for clarity.
};

ОТРЕДАКТИРУЙТЕ ИЗ-ЗА "НЕ, ЧТО Я ИЩУ" ОТВЕТЫ:

Точно, каковы последствия каждого маршрута. Не давайте неопределенные ответы как "он, не будет разрушен правильно". Скажите мне точно, что произойдет. Я - немного компьютерный фанат блока.

Редактирование 2:

Я хорошо знаю, что "виртуальный" тег означает, что деструктор не назовут, если удалено через указатель на полученный, но (я думаю), этот вопрос в конечном счете сводится к "ему, безопасно опустить тот деструктор, поскольку действительно ли это действительно тривиально?"

РЕДАКТИРОВАНИЕ 3:

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

10
задан Justin Ethier 13 November 2012 в 15:35
поделиться

6 ответов

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

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

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

13
ответ дан 3 December 2019 в 15:34
поделиться

Ответ в основном на правку:

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

3
ответ дан 3 December 2019 в 15:34
поделиться

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

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

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

2
ответ дан 3 December 2019 в 15:34
поделиться

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

Например,

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

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

3
ответ дан 3 December 2019 в 15:34
поделиться

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

public class Base 
{
 //...
}

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

//...

Base* b = new Derived();

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

delete b;

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

0
ответ дан 3 December 2019 в 15:34
поделиться

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

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

7
ответ дан 3 December 2019 в 15:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: