Виртуальные деструкторы полезны, когда вы можете удалить экземпляр производного класса с помощью указателя на базовый класс:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
Здесь вы заметите, что я не объявлял деструктор базы virtual
. Теперь давайте посмотрим на следующий фрагмент:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Поскольку деструктор базы не является virtual
, а b
является Base*
, указывающим на объект Derived
, delete b
имеет неопределенное поведение :
[В
blockquote>delete b
], если статический тип подлежащего удалению объекта отличается от его динамического типа, статический тип должен быть базовый класс динамического типа объекта, подлежащего удалению, и статический тип должен иметь виртуальный деструктор или поведение не определено.В большинстве реализаций вызов деструктора будет разрешен как и любой не виртуальный код, что означает, что деструктор базового класса будет вызываться, но не тот, который был получен из производного класса, что приведет к утечке ресурсов.
Подводя итог, всегда создавайте деструкторы базовых классов
virtual
, когда они предназначены для управления полиморфно.Если вы хотите предотвратить удаление экземпляра с помощью указателя базового класса, вы можете сделать деструктор базового класса защищенным и не виртуальным; при этом компилятор не позволит вам называть
delete
указателем базового класса.Вы можете узнать больше о деструкторе виртуальности и виртуального базового класса в этой статье от Herb Sutter .