Не, немного не так. Деструктор базового класса из деструктора производного вызывать не надо (да и нельзя), он сам вызовется автоматически. Проблема в другом: деструктор производного класса может быть не вызван!
Представьте себе такую ситуацию:
class Person
{
~Person() { } // деструктор не виртуальный
};
class Spy : public Person
{
Gadget* gadgets;
public:
Spy() { gadgets = new Gadget[10]; }
~Spy() { delete[] gadgets; }
};
std::vector<Person> citizens;
// наполнить значениями
for (Person citizen : citizens)
delete citizen;
Что случится, если в списке будет один Spy? А вот что: при уничтожении объекта типа Spy по указателю типа Person* вызовется невиртуальный деструктор ~Person. Значит, память под массив gadgets не будет освобождена. Вот вам и утечка памяти.
На самом деле, кроме утечки памяти может произойти любая другая неприятность, ведь деструктор, на который вы рассчитывали, не вызовется! Например, может не закрыться файл, и при следующей попытке его открыть программа вылетит. Или не отпустится мьютекс, и при попытке его получить программа зависнет. Ну и ещё куча всяких катастроф может произойти.
Хуже того, по стандарту отсутствие виртуального деструктора в данном случае является undefined behaviour, то есть, программа имеет право сделать что угодно: отформатировать винчестер, признаться в любви к вашей химичке через «Вконтакте» или подлить валерьянки в миску с Вискасом.
Да, а в C деструкторов нету вовсе.
– M. Williams Jul 30 '13 at 09:01Формально говоря, отсутствие вызова деструктора
Deriveне является следствием забытогоvirtual. Это undefined behavior, и компилятор вправе, например, просто уронить ваше приложение с segfault'ом.Если класс подразумевает наследование (или речь идет об интерфейсе), то деструктор должен быть
public virtualилиprotected nonvirtual. Вторая часть этого утверждения не менее важна, чем первая, поскольку позволяет вообще запретить удаление объектов через base class pointer.virtualмоментально приводит к coredump'у.