Деструкторы всегда должны быть виртуальными
Рассмотрим такой код:
class base
{
char *p;
~base() { p = new char[SOME_SIZE]; }
base() { delete p; }
};
class derived : public base
{
char *dp;
~derived() { dp = new char[[SOME_SIZE]; }
derived() { delete dp; }
};
Теперь рассмотрим этот вызов:
base *p = new derived;
// ...
delete p;
Запомните, что компилятор не знает, что p на самом деле указывает на объект производного класса. Он исходит из того, что
p
указывает на объявленный тип base. Следовательно, delete
p
в действительности превращается в:
_base__destructor(p);
free(p);
Деструктор производного класса никогда не вызывается. Если вы переопределите эти классы, сделав деструктор виртуальным:
virtual ~base() { /* ... */ }
то компилятор получит доступ к нему при помощи таблицы виртуальных функций, просто как к любой другой виртуальной функции. Так как деструктор теперь виртуальный, то delete p
превращается в:
( p-_vtable[DESTRUCTOR_SLOT] ) (p);
Так как p
указывает на объект производного класса, то вы получаете деструктор производного класса, который после выполнения компоненты производного класса
вызывает деструктор базового.