2009-03-24 13 views
267

Al anular una clase en C++ (con un destructor virtual), estoy implementando el destructor nuevamente como virtual en la clase heredada, pero ¿necesito llamar al destructor base?¿Debo llamar explícitamente al destructor virtual base?

Si es así me imagino que es algo como esto ...

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

    // Some destructing specific to MyChildClass 
} 

Estoy en lo cierto?

Respuesta

365

No, los destructores se llaman automáticamente en el orden inverso de la construcción. (Las clases base duran). No llame a los destructores de la clase base.

+0

¿Qué hay de los destructores virtuales puros? Mi enlazador está tratando de llamarlo al final del destructor no virtual de mi clase heredada; – cjcurrie

+32

no puede tener un destructor virtual puro sin un cuerpo. Solo dale un cuerpo vacío. Con un método virtual puro regular, la función principal se llama en su lugar, con destructores, todos son llamados, por lo que debe proporcionar un cuerpo. La = 0 solo significa que debe ser anulada, por lo que sigue siendo una construcción útil si la necesita. –

+1

Esta pregunta podría estar relacionada y ayuda [questions/15265106/c-a-missing-vtable-error] (http://stackoverflow.com/questions/15265106/c-a-missing-vtable-error). –

80

No, no necesita llamar al destructor base, el destructor derivado lo llamará siempre a usted. Please see my related answer here for order of destruction.

Para entender por qué quiere un destructor virtual en la clase base, consulte el código de abajo:

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


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

Al hacer:

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

Entonces, si usted no tiene un destructor virtual en B, solo se llamaría ~ B(). Pero como tiene un destructor virtual, primero se llamará ~ D(), luego ~ B().

+12

Incluya la salida del programa (pseudo). ayudará al lector –

6

No. Se llama automáticamente.

25

Lo que dijeron los demás, pero también tenga en cuenta que no tiene que declarar el destructor virtual en la clase derivada. Una vez que declara un destructor virtual, como lo hace en la clase base, todos los destructores derivados serán virtuales, ya sea que los declare así o no. En otras palabras:

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

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

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

¿Qué pasa si ~ B no se declara virtual? Es ~ C todavía virtual? – Will

+4

Sí. Cuando un método virtual (cualquiera, no solo el destructor) se declara virtual, todas las anulaciones de ese método en las clases derivadas son automáticamente virtuales. En este caso, incluso si no declaras ~ B virtual, todavía lo es, y también lo es ~ C. – boycy

+1

Pero a diferencia de otros métodos reemplazados que tienen el mismo nombre y parámetros de sus métodos correspondientes en la clase base, el nombre del destructor es diferente. ¿Importará? @boycy –

9

No. A diferencia de otros métodos virtuales, donde desea llamar explícitamente al método Base del Derivado de 'cadena' de la llamada, el compilador genera código para llamar a los destructores en el orden inverso en el que sus constructores fueron llamados.

2

No, nunca llama al destructor de la clase bese, que siempre es llamado automáticamente como otros han señalado, pero aquí es una prueba de concepto con resultados:

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

La salida es:

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

Si configura el destructor de la clase base como uno virtual, entonces los resultados son los mismos que en el caso 1 & 2.

Cuestiones relacionadas