2010-06-03 10 views
10

¿Las interfaces necesitan un destructor virtual, o el autogenerado está bien? Por ejemplo, ¿cuál de los siguientes dos fragmentos de código es el mejor y por qué? Tenga en cuenta que esta es la clase entera. No hay otros métodos, variables, etc. En Java-speak, esta es una "interfaz".Destructores virtuales para las interfaces

class Base 
{ 
public: 
    virtual void foo() = 0; 
    virtual ~Base() {} 
}; 

O ...

class Base 
{ 
public: 
    virtual void foo() = 0; 
    ~Base() {} // This line can be omitted, but included for clarity. 
}; 

edición debido a "NO LO QUE ESTOY BUSCANDO" RESPUESTAS:

exactamente cuáles son las consecuencias de cada ruta. No brinde respuestas vagas como "no se destruirá correctamente". Por favor dime exactamente lo que sucederá Soy un poco nerd de ensamblaje.

Edición 2:

Soy muy consciente de que la etiqueta de "virtual" significa que el destructor no se llama si se suprime a través de un puntero a derivados, pero (creo) a esta pregunta se reduce en última instancia a "¿es seguro omitir ese destructor, porque es realmente trivial?"

Datos 3:

Mi segunda edición es simplemente errónea y desinformación. Por favor, lea los comentarios de personas inteligentes reales para obtener más información.

+3

Tienes la definición de virtual invertido, tipo de. La etiqueta virtual no significa que no se llamará al destructor base si se borra a través de un puntero a derivado, lo que ocurre siempre. En cambio, la etiqueta virtual significa que se llamará al destructor * derived * si elimina el objeto mediante un puntero del tipo de clase * base *. –

+1

@Jordan: Dios mío, creo que tienes razón. –

+4

"Soy un poco nerd de montaje". Eso es desafortunado, ya que C++ no dice nada sobre la generación de ensamblaje. Si desea ver cómo lo maneja un compilador en particular, compile un código y observe el resultado. Y -1 simplemente a tu actitud; no haga una pregunta y diga a todos los que respondieron "usted lo tiene al revés" y desmárquelos. Estás haciendo una pregunta por alguna razón, ¿verdad? – GManNickG

Respuesta

13

Considere el siguiente caso:

Base *Var = new Derived(); 
    delete Var; 

Se necesita el destructor virtual, de lo contrario cuando se elimina Var, nunca va a ser llamada la clase derivada destructor.

+0

No tiene ningún destructor que valga la pena mencionar. –

+2

@wowus: * Base * no tiene ningún destructor que valga la pena mencionar. Usted no sabe lo que hace el destructor Derived. –

+2

Te estás perdiendo el punto clave aquí. 'Derived :: ~ Derived' no se llamará a menos que declares Base :: Base como virtual. –

0

No ... los destructores virtuales no se generan automáticamente. Debes declararlos explícitamente en tu clase base. Pero no necesitará declarar sus destructores virtuales para las clases secundarias de Base. Esto es hecho por el compilador. El compilador también se asegurará de que los destructores se invoquen en orden inverso de construcción (de derivado a base).

public class Base 
{ 
//... 
} 

public class Derived 
{ 
    int i = 0; 
    //... 
} 

//... 

Base* b = new Derived(); 

Si no tiene un destructor virtual

delete b; 

causaría pérdidas de memoria (al menos 4 bytes para el campo entero), porque sería destruir solamente Base y no Derived. La virtualidad asegura que las clases derivadas también se destruyan. No tendrá que declarar un constructor virtual en Derived, esto será inferido por el compilador, si declaró un destructor virtual en Base.

3

Debe utilizar un destructor virtual si espera que las personas intenten eliminar objetos de una clase derivada mediante punteros o referencias de la clase padre. Si este es el caso, entonces sin un destructor virtual, la clase derivada nunca será destruida adecuadamente.

Por ejemplo,

Derived::~Derived() { // important stuff } 
Base *foo = new Derived(); 
delete foo; 

Sin un destructor virtual de la base, no se llamará del Derivado destructor, y lo importante, por tanto, nunca va a pasar.

+4

En realidad, lo que ocurre en este caso no está definido por C++. –

2

En general, un destructor debe ser o bien (1) pública y virtual, o (2) protegido y no virtual.

Suponiendo que nunca espere que alguien elimine una instancia de clase mediante un puntero de interfaz, un destructor no virtual protegido es 100% seguro.

Si alguien intenta eliminar un puntero de interfaz en el caso (2), obtendrá un error en tiempo de compilación.

+0

¿Quisiste decir un "destructor" en tu primera oración? –

+0

Lo hice. Ups, buena captura – zildjohn01

7

Si elimina un objeto de clase derivado mediante un puntero de clase base en C++, el resultado es un comportamiento indefinido. UB es algo que realmente quieres evitar, por lo que debes dar a las clases base un destructor virtual. Citando el estándar de C++, la sección 5.3.5:

si el tipo estático del operando es diferente de su tipo dinámico, el tipo estático será una clase base de tipo dinámico del operando y el tipo estático tendrá un destructor virtual o el comportamiento es undefined.

3

En respuesta a la mayoría de la edición:

Nadie le puede decir lo que va a ocurrir porque el resultado es "un comportamiento indefinido". Cuando elimina una clase derivada a través de un puntero a una base que no tiene un destructor virtual, la implementación se puede descomponer de muchas maneras.

Cuestiones relacionadas