2009-03-24 15 views
267

Quando si esegue l'override di una classe in C++ (con un distruttore virtuale) sto implementando di nuovo il distruttore come virtuale nella classe ereditaria, ma devo chiamare il distruttore di base?Devo chiamare esplicitamente il distruttore virtuale di base?

Se quindi immagino che sia qualcosa di simile ...

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

    // Some destructing specific to MyChildClass 
} 

ho ragione?

risposta

365

No, i distruttori vengono chiamati automaticamente nell'ordine inverso di costruzione. (Le classi base durano). Non chiamare i distruttori della classe base.

+0

E i puri distruttori virtuali? Il mio linker sta cercando di chiamarlo alla fine del distruttore non virtuale della mia classe ereditata; – cjcurrie

+32

non puoi avere un distruttore virtuale puro senza un corpo. Dagli un corpo vuoto. Con un normale metodo virtuale puro, la funzione di override viene invece chiamata, con i distruttori, vengono tutti chiamati, quindi devi fornire un corpo. Il = 0 significa semplicemente che deve essere sovrascritto, quindi è ancora un costrutto utile se ne hai bisogno. –

+1

Questa domanda potrebbe essere correlata e aiutare [domande/15265106/c-a-missing-vtable-error] (http://stackoverflow.com/questions/15265106/c-a-missing-vtable-error). –

80

No non è necessario chiamare il distruttore di base, un distruttore di base viene sempre chiamato dal distruttore derivato. Please see my related answer here for order of destruction.

Per comprendere il motivo per cui si desidera un distruttore virtuale nella classe base, si prega di consultare il codice qui sotto:

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


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

Quando si esegue:

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

Quindi se non si dispone di un distruttore virtuale in B, sarebbe chiamato solo ~ B(). Ma dal momento che hai un distruttore virtuale, prima verrà chiamato ~ D(), quindi ~ B().

+12

Si prega di includere l'output del programma (pseudo). aiuterà il lettore. –

6

No. Viene chiamato automaticamente.

25

Ciò che gli altri hanno detto, ma anche notare che non è necessario dichiarare il distruttore virtuale nella classe derivata. Una volta dichiarato un distruttore virtuale, come si fa nella classe base, tutti i distruttori derivati ​​saranno virtuali sia che li dichiariate o meno. In altre parole:

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

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

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

cosa succede se ~ B non è dichiarato virtuale? ~ C è ancora virtuale? – Will

+4

Sì. Quando un metodo virtuale (qualsiasi, non solo il distruttore) viene dichiarato virtuale, tutti gli override di quel metodo nelle classi derivate sono automaticamente virtuali. In questo caso, anche se non dichiari ~ B virtuale, lo è ancora, e così è ~ C. – boycy

+1

Ma a differenza di altri metodi sovrascritti che hanno lo stesso nome e i parametri dei loro metodi corrispondenti nella classe base, il nome del distruttore è diverso. Sarà importante? @boycy –

9

No. A differenza di altri metodi virtuali, dove si sarebbe esplicitamente chiamare il metodo di base della derivata per 'catena' la chiamata, il compilatore genera codice per chiamare i distruttori in ordine inverso in cui i loro costruttori furono chiamati.

2

No, mai chiamata la classe distruttore bese, si è sempre chiamato automaticamente come altri hanno fatto notare, ma qui è la prova di concetto con risultati:

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

L'output è:

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

Se si imposta il distruttore della classe base come virtuale, quale dovrebbe essere, i risultati sono gli stessi del caso 1 & 2.

Problemi correlati