2009-03-24 9 views
267

Podczas przesłonięcia klasy w C++ (z wirtualnym destruktorem) wdrażam destruktor ponownie jako wirtualny w klasie dziedziczącej, ale czy muszę wywoływać podstawowy destruktor?Czy muszę jawnie wywoływać podstawowy wirtualny destruktor?

Jeśli więc sobie wyobrazić, że jest coś takiego ...

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

    // Some destructing specific to MyChildClass 
} 

mam rację?

Odpowiedz

365

Nie, destruktory są wywoływane automatycznie w kolejności odwrotnej do budowy. (Klasy bazowe trwają). Nie wywołuj destruktorów klasy podstawowej.

+0

Co z czystymi wirtualnymi destruktorami? Mój linker próbuje wywołać to na końcu nie-wirtualnego destruktora mojej odziedziczonej klasy; – cjcurrie

+32

nie można mieć czystego wirtualnego destruktora bez ciała. Po prostu daj mu puste ciało. W przypadku zwykłej metody czysto wirtualnej zamiast tego wywoływana jest funkcja nadrzędna, z destruktorami, wszystkie są wywoływane, więc trzeba dostarczyć ciało. Wartość = 0 oznacza po prostu, że musi być nadpisana, więc nadal jest użytecznym konstruktem, jeśli jej potrzebujesz. –

+1

To pytanie może być powiązane i pomóc [pytania/15265106/c-a-missing-vtable-error] (http://stackoverflow.com/questions/15265106/c-a-missing-vtable-error). –

80

Nie musisz wywoływać destruktora bazowego, destruktor bazowy jest zawsze wywoływany przez wyprowadzony destruktor. Please see my related answer here for order of destruction.

Aby zrozumieć, dlaczego chcesz wirtualny destruktor w klasie bazowej, patrz poniższy kod:

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


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

Kiedy zrobić:

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

następnie, jeśli nie masz wirtualny destruktor w B zostanie wywołane tylko ~ B(). Ale ponieważ masz wirtualny destruktor, najpierw zostanie wywołana ~ D(), a następnie ~ B().

+12

Proszę podać wynik programu (pseudo). to pomoże czytelnikowi. –

6

Nie. Jest automatycznie wywoływana.

25

Co inni mówili, ale zauważmy również, że nie trzeba deklarować wirtualnego destruktora w klasie pochodnej. Po zadeklarowaniu wirtualnego destruktora, tak jak w klasie bazowej, wszystkie wyprowadzone destruktory będą wirtualne niezależnie od tego, czy je zadeklarujesz, czy nie. Innymi słowy:

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

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

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

co jeśli ~ B nie jest deklarowany jako wirtualny? Czy ~ C jest nadal wirtualny? – Will

+4

Tak. Kiedy wirtualna metoda (dowolna, nie tylko destruktor) jest deklarowana jako wirtualna, wszystkie przesłonięcia tej metody w klasach pochodnych są automatycznie wirtualne. W tym przypadku, nawet jeśli nie zadeklarujesz ~ B, to nadal jest, a więc ~ C. – boycy

+1

Ale w przeciwieństwie do innych przesłoniętych metod o tej samej nazwie i parametrach odpowiadających im metod w klasie bazowej, nazwa destruktora jest inna. Czy to ma znaczenie? @boycy –

9

nr przeciwieństwie do innych metod wirtualnych, gdzie jawnie wywołać metodę bazą pochodny do „łańcucha” rozmowy, kompilator generuje kod, aby zadzwonić do destruktorów w odwrotnej kolejności, w jakiej ich konstruktorzy zostali nazwani.

2

Nie, nigdy nie wywołać Beše klasy destruktora, zawsze jest wywoływana automatycznie jak inni zwrócili uwagę, ale tutaj jest dowód koncepcji z wynikami:

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; 
} 

Wyjście jest:

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

Jeśli ustawisz destruktor klasy podstawowej jako wirtualny, który powinieneś, wyniki będą takie same jak w przypadku 1 & 2.

Powiązane problemy