2008-12-09 22 views
44

Java y C# admiten la noción de clases que no se pueden usar como clases base con las palabras clave final y sealed. En C++, sin embargo, no hay una buena manera de evitar que una clase se derive de lo cual deja al autor de la clase con un dilema, ¿debería cada clase tener un destructor virtual o no?¿Debería cada clase tener un destructor virtual?


Editar: Como C++ 11 esto ya no es cierto, se puede especificar que una clase es final.


Por un lado dar a un objeto un destructor virtual significa que tendrá un vtable y por lo tanto consumir 4 (o 8 en máquinas de 64 bits) bytes adicionales por cada objeto para el vptr.

Por otro lado, si alguien más tarde deriva de esta clase y elimina una clase derivada a través de un puntero a la clase base, el programa estará mal definido (debido a la ausencia de un destructor virtual) y optimizando francamente puntero por objeto es ridículo.

En el gripping hand teniendo un destructor virtual (posiblemente) se anuncia que este tipo está destinado a ser utilizado polimórficamente.

Algunas personas piensan que necesita una razón explícita para no usar un destructor virtual (como es el subtexto de this question) y otros dicen que debe usarlas solo cuando tenga motivos para creer que su clase se derivará de, ¿qué usted piensa?

+0

Ya hay preguntas para los pros y los contras: ¿es este un duplicado, o es una encuesta de opinión? Si esto último, tal vez debería crear respuestas de "sí" y "no" para votar, entonces cierre la pregunta. Creo que esa es la forma recomendada de implementar una encuesta de opción múltiple en SO. –

+0

Duplicados: http://stackoverflow.com/questions/270917/why-should-i-declare-a-virtual-destructor-for-an-abstract-class-in-c, http://stackoverflow.com/questions/300986/when-should-you-not-use-virtual-destructores –

+6

"y la optimización franca para un puntero por objeto es ridículo". No es ridículo para objetos pequeños. C++ 0x está agregando un contenedor forward_list, precisamente porque a veces un puntero por sobrecarga de objetos es demasiado, a partir de los requisitos de espacio y tiempo. –

Respuesta

26

La pregunta es en realidad, ¿desea aplicar reglas sobre cómo deben usarse sus clases? ¿Por qué? Si una clase no tiene un destructor virtual, cualquiera que use la clase sabe que no se pretende derivar de ella, y qué limitaciones se aplican si la prueba de todos modos. ¿No es eso lo suficientemente bueno?

¿O necesita el compilador para lanzar un error grave si alguien se atreve para hacer algo que no había previsto?

Proporcione a la clase un destructor virtual si desea que las personas se deriven de él. De lo contrario, no lo haga, y suponga que cualquier persona que use su código es lo suficientemente inteligente como para usar su código correctamente.

+6

@jalf: si derivan de él Y quieren usarlo de forma polimórfica/ – Oszkar

2

Yo "no" a la pregunta general. No cada clase necesita uno. Si puede saber que la clase nunca debe heredarse, entonces no hay necesidad de incurrir en la sobrecarga menor. Pero si hay una posibilidad, estar en el lado seguro y poner uno allí.

8

No! Los destructores virtuales se usan solo cuando un objeto de una clase derivada se elimina a través de un puntero de clase base. Si su clase no pretende servir como base en este escenario, no convierta el destructor en virtual; estaría enviando un mensaje incorrecto.

+0

Entonces, ¿cómo anticipas cada instancia en la que tu código es útil? Tal vez haya alguna instancia en la que su clase, que debe ser usada de forma no polimórfica por usted, sea útil solo como clase base en alguna instancia muy específica. – v010dya

53

Cada clase abstracta o bien debe tener una,

  • destructor protegido, o,
  • destructor virtual.

Si tiene un destructor público no virtual, eso no es bueno, ya que permite a los usuarios eliminar mediante ese puntero un objeto derivado. Como todos sabemos, ese es un comportamiento indefinido.

Para una clase que no se pretende borrar a través de un puntero, no hay ninguna razón para tener un destructor virtual. No solo desperdiciaría recursos, sino que, lo que es más importante, daría a los usuarios una pista equivocada. Solo piense qué sentido de mierda le daría dar a std::iterator un destructor virtual.

+2

O struct tm desde , que dejaría de ser POD y por lo tanto ya no sería compatible con las convenciones de llamadas de C. –

+0

gran respuesta, litb. Iré a cambiar todo mi código ahora mismo. –

0

Añadiré que ha habido ocasiones en que me he rascado la cabeza por un tiempo en los destructores que no se llamaban cuando olvidé una virtual en la clase principal o secundaria. Sin embargo, creo que sé que debo buscar eso ahora.:)

Alguien podría argumentar que hay veces que la clase padre hace algo en su destructor que un niño no debería hacer ... pero eso es probablemente un indicador de que algo anda mal con la estructura de herencia de todos modos.

4

Comprobar this article from Herb Sutter:

Pauta # 4: Un destructor de la clase base debe ser pública y virtual, o protegido y no virtual.

+8

Tenga en cuenta que él está hablando de clases que están destinadas a ser * clases base * esta pregunta es específicamente sobre clases no diseñadas para ser clases base. – Motti

0

La clase base se convierte en clase abstracta, cuando contiene al menos una función virtual pura. Si Base no tiene un destructor virtual y Derivado (derivado de Base) lo hace, puede destruir de forma segura un objeto derivado a través de un puntero de objeto Derivado pero no a través de un puntero de objeto Base.

-3
include<iostream> using namespace std; 

class base { 
    public: base() { 
     cout << "In base class constructor" << endl; 
    } 

    virtual ~base() { 
     cout << "in base class destuctor" << endl; 
    } 
}; 

class derived : public base { 
    public: derived() { 
     cout << "in derived class constructor" << endl; 
    } 

    ~derived() { 
     cout << "in derived class destructor" << endl; 
    } 
}; 

int main() { 
    base *b; // pointer to the base 
    class b = new derived; // creating the derived class object using new 
    keyword; 
    delete b; 
    return 0; 
} 
+0

chico no pude poner mi respuesta en una secuencia .. – ashutosh

+0

Simplemente pegue su código, selecciónelo todo y haga clic en '{}'. Pero lo que publicaste no responde la pregunta anterior. Las respuestas de solo código generalmente no son lo suficientemente buenas aquí, debe explicar por qué el código que proporciona responde la pregunta publicada. – Mat

+0

No ha respondido la pregunta, simplemente se muestra cómo hacerlo. – iblamefish

Cuestiones relacionadas