Нужно ли явно вызывать базовый виртуальный деструктор? - PullRequest
313 голосов
/ 24 марта 2009

При переопределении класса в C ++ (с помощью виртуального деструктора) я снова реализую деструктор как виртуальный в классе наследования, но нужно ли вызывать базовый деструктор?

Если так, я представляю, что-то вроде этого ...

MyChildClass::~MyChildClass() // virtual in header
{
    // Call to base destructor...
    this->MyBaseClass::~MyBaseClass();

    // Some destructing specific to MyChildClass
}

Я прав?

Ответы [ 6 ]

421 голосов
/ 24 марта 2009

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

86 голосов
/ 24 марта 2009

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

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

class B
{
public:
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
    }
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

Когда вы делаете:

B *pD = new D();
delete pD;

Тогда, если у вас нет виртуального деструктора в B, будет вызван только ~ B (). Но так как у вас есть виртуальный деструктор, сначала будет вызван ~ D (), а затем ~ B ().

26 голосов
/ 24 марта 2009

То, что сказали другие, но также обратите внимание, что вам не нужно объявлять виртуальный деструктор в производном классе. После объявления виртуального деструктора, как в базовом классе, все производные деструкторы будут виртуальными, независимо от того, объявите вы их так или нет. Другими словами:

struct A {
   virtual ~A() {}
};

struct B : public A {
   virtual ~B() {}   // this is virtual
};

struct C : public A {
   ~C() {}          // this is virtual too
};
10 голосов
/ 24 марта 2009

Нет. В отличие от других виртуальных методов, где вы явно вызываете метод Base из Derived для «цепочки» вызова, компилятор генерирует код для вызова деструкторов в обратном порядке, в котором были вызваны их конструкторы.

7 голосов
/ 21 сентября 2017

Нет, вы никогда не вызываете деструктор базового класса, он всегда вызывается автоматически, как указали другие, но вот подтверждение концепции с результатами:

class base {
public:
    base()  { cout << __FUNCTION__ << endl; }
    ~base() { cout << __FUNCTION__ << endl; }
};

class derived : public base {
public:
    derived() { cout << __FUNCTION__ << endl; }
    ~derived() { cout << __FUNCTION__ << endl; } // adding call to base::~base() here results in double call to base destructor
};


int main()
{
    cout << "case 1, declared as local variable on stack" << endl << endl;
    {
        derived d1;
    }

    cout << endl << endl;

    cout << "case 2, created using new, assigned to derive class" << endl << endl;
    derived * d2 = new derived;
    delete d2;

    cout << endl << endl;

    cout << "case 3, created with new, assigned to base class" << endl << endl;
    base * d3 = new derived;
    delete d3;

    cout << endl;

    return 0;
}

Вывод:

case 1, declared as local variable on stack

base::base
derived::derived
derived::~derived
base::~base


case 2, created using new, assigned to derive class

base::base
derived::derived
derived::~derived
base::~base


case 3, created with new, assigned to base class

base::base
derived::derived
base::~base

Press any key to continue . . .

Если вы установите деструктор базового класса как виртуальный, что и должно быть, тогда результаты для случая 3 будут такими же, как для случаев 1 и 2.

6 голосов
/ 24 марта 2009

Нет. Он автоматически вызывается.

...