c++ - ¿Debería cada clase tener un destructor virtual?
virtual-destructor (8)
Java y C # admiten la noción de clases que no pueden utilizarse 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?
Editar: Dado que C ++ 11 ya no es cierto, 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 (u 8 en máquinas de 64 bits) bytes adicionales por 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 la optimización franca para un puntero por objeto es ridículo.
En la mano de agarre que tiene un destructor virtual (podría decirse) anuncia que este tipo está destinado a ser utilizado polimórficamente.
Algunas personas piensan que necesitas una razón explícita para no usar un destructor virtual (como es el subtexto de esta pregunta ) y otros dicen que debes usarlas solo cuando tienes razones para creer que tu clase se derivará de, ¿qué haces ? ¿pensar?
¡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.
Añadiré que ha habido momentos en los 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 de padres hace algo en su destructor que un niño no debería hacer ... pero de todos modos es un indicador de que algo está mal con la estructura de tu herencia.
La pregunta es, realmente, ¿quieres hacer cumplir las reglas sobre cómo deberían usarse tus 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 que el compilador arroje un error difícil si alguien se atreve a hacer algo que no había anticipado?
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.
Yo "no" a la pregunta general. No todas las clases necesitan una. 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í.
Consulta este artículo de Herb Sutter :
Directriz # 4: Un destructor de clase base debe ser público y virtual, o protegido y no virtual.
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.
Cada clase abstracta 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 a través de ese puntero un objeto derivado. Como todos sabemos, ese es un comportamiento indefinido.
Para una clase que no se pretende borrar mediante un puntero, no existe razón alguna 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 en el mal sentido que tendría darle a std::iterator
un destructor virtual.
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;
}