Правила программирования на Си и Си++

       

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


Рассмотрим такой код:

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

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

вызывает деструктор базового.



Содержание раздела