Виртуальные деструкторы для интерфейсов - PullRequest
10 голосов
/ 04 июня 2010

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

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

Ответы [ 6 ]

13 голосов
/ 04 июня 2010

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

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

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

7 голосов
/ 04 июня 2010

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

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

3 голосов
/ 04 июня 2010

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

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

3 голосов
/ 04 июня 2010

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

Например,

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

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

2 голосов
/ 04 июня 2010

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

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

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

0 голосов
/ 04 июня 2010

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

public class Base 
{
 //...
}

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

//...

Base* b = new Derived();

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

delete b;

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

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