33. C++ Виртуальный деструктор

Виртуальный деструктор

Как известно, указатель на базовый класс является указателем и на классы наследники, а также можно создать объект класса (как переменную) в динамической памяти и присвоить адресу указателю на базовый класс.
т.е.

class A {//code};
class B : public A {//code};

int main ()
{ 
  A *ptrA=new B;
  delete ptrA;
    return 0;
}

Что в этом случае произойдет?
При таком вызове в динамической памяти создается объект класса B, размер которого обычно больше размера класса A (т.к. класс A входит в класс B).
При таком вызове указатель *ptpA содержит указатель на часть класса B которая соответствует A., следовательно при вызове оператора delete *ptrA; удалится лишь «подкласс A» входящий в класс B, в этом случае вызовется деструктор класса A, а часть соответствующая классу B так и останется в динамической памяти, а мы получим утечку.
Можно сказать, что указатель *ptpA ничего не знает о классе B.

Чтобы этого избежать нужно применить деструктор сделать виртуальным:

class A
{
   public:
    A(){}
    virtual ~A(){}
    //code
};
class B : public A
{
   public:
    B(){}
    ~B() override {}
    //code
};

В этом случае в коде A *ptpA=new B будет подставлен адрес виртуального деструктора (т.е. деструктор класса B), и после вызова деструктора (удаления) класса B будет вызван деструктор класса A.

Чисто виртуальный деструктор:
Аналогично абстрактным классам с чисто виртуальными методами можно создать чисто виртуальный деструктор, общая идея примерно такая же, синтаксис приведен ниже.

class A
{
   public:
    A(){}
    virtual ~A() =0;
    //code
};
A:: A(){}; //ВАЖНО сделать внешнюю пустую функцию

На мой взгляд чисто виртуальный деструктор может иметь смысл, если в каждом классе наследнике будет по-своему (в разном объеме) выделяться память.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *