2009-03-24 3 views
267

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

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

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

    // Some destructing specific to MyChildClass 
} 

Я прав?

ответ

365

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

+0

Что относительно чистых виртуальных деструкторов? Мой компоновщик пытается вызвать его в конце не виртуального деструктора унаследованного класса; – cjcurrie

+32

вы не можете иметь чистый виртуальный деструктор без тела. Просто дайте ему пустое тело. С помощью обычного чистого виртуального метода вместо него вызывается функция переопределения, с деструкторами, все они называются, поэтому вам нужно предоставить тело. Значение = 0 означает, что оно должно быть переопределено, поэтому все-таки полезная конструкция, если вам это нужно. –

+1

Этот вопрос может быть связан и помочь [вопросы/15265106/c-a-missing-vtable-error] (http://stackoverflow.com/questions/15265106/c-a-missing-vtable-error). –

80

Нет, вам не нужно вызывать базовый деструктор, базовый деструктор всегда вызывается производным деструктором. Please see my related answer here for order of destruction.

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

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().

+12

Пожалуйста, включите вывод программы (псевдо). это поможет читателю. –

6

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

25

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

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

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

struct C : public A { 
    ~C() {}   // this is virtual too 
}; 
+1

Что делать, если ~ B не объявляется виртуальным? Является ли C еще виртуальным? – Will

+4

Да. Когда виртуальный метод (любой, а не только деструктор) объявляется виртуальным, все переопределения этого метода в производных классах автоматически виртуальны. В этом случае, даже если вы не объявляете ~ B виртуальным, оно все еще есть, и это ~ C. – boycy

+1

Но в отличие от других переопределенных методов, имеющих одно и то же имя и параметры их соответствующих методов в базовом классе, имя деструктора отличается. Будет ли это важно? @boycy –

9

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

2

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

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 . . . 

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

Смежные вопросы