В языке программирования C++ деструктор базового (полиморфного) класса должен объявляться виртуальным. Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
Внимание!
Забегая вперед, надо отметить важную вещь: при описании виртуального деструктора нужно обязательно написать его реализацию, даже если она "пустая". Если забыть написать реализацию, то компиляция может пройти без ошибок и предупреждений, но ошибка возникнет в рантайме.
Обычным является использование виртуального деструктора в классах, имеющих виртуальные функции. Более того, gcc, например, выдаст вам предупреждение, если вы не сделаете виртуальным деструктор, объявив хотя бы одну виртуальную функцию. Это происходит из-за того, что если в классе есть хотя бы одна виртуальная функция, то в скомпилированном представлении класса появляется таблица виртуальных функций VTABLE, а сам класс начинает считаться виртуальным. Компилятор видит, что класс виртуальный, и рекомендует сделать деструктор виртуальным.
Часто можно встретить миф: «Виртуальный деструктор нужен лишь в том случае, когда на деструктор классов-потомков возлагаются какие-то нестандартные функции. Если деструктор потомка не отличается по функционалу от родителя, то делать его виртуальным нет особого смысла». Да, это может и будет работать «сейчас», но может сыграть злую шутку в будущем, да и в общем-то не очень верно.
Основная проблема в том, что если деструктор не виртуальный, то будет вызван деструктор того типа, какой заявлен в указателе. А ведь указатель запросто может иметь тип базового класса, хотя указывает на объект производного класса. Однако будет правильнее, что бы для объектов-потомков вызывались свои деструкторы. Просто стоит принять это как правило, иначе в будущем могут быть очень большие проблемы с отладкой непонятно почему текучих в плане памяти программ.
Пример определения виртуального деструктора:
class Record
{
public:
Record();
virtual ~Record();
...
};
Пример реализации виртуального деструктора (синтаксис реализации ничем не отличается от обычного деструктора):
Record::~Record()
{
...
}
Примечание: для лучшего понимания, как на самом деле вызываются виртуальные методы (включая деструктор), подготовлена следующая статья: Понимание наследования и механизма виртуальных методов в C++ .
|