Un destructor virtual es un destructor declarado con la palabra clave virtual en la clase base. Esto garantiza que se llame al destructor de la clase derivada al eliminar un objeto a través de un puntero a la clase base.
class Base { public: virtual ~Base() { /* ... */ } }; class Derived : public Base { public: ~Derived() override { /* ... */ } }; Base* ptr = new Derived(); delete ptr; // Se llamarán ambos destructores
Sin un destructor virtual, el comportamiento puede ser incorrecto: el destructor de la clase derivada no se llamará, lo que puede provocar una fuga de recursos.
¿Es necesario declarar un destructor como virtual si en su clase base no hay ninguna función virtual?
Respuesta: Sí, si se espera que la clase se sobrescriba con eliminación a través de un puntero al tipo base. Incluso si no hay otras funciones virtuales, la virtualidad del destructor es necesaria para la correcta eliminación de los descendientes.
class Shape { public: virtual ~Shape() {} };
Historia 1
En un gran proyecto de una biblioteca gráfica, al eliminar objetos de dibujo a través de un puntero a la clase base, se filtraban recursos de OpenGL (buffers, texturas) — las liberaciones correspondientes estaban en los destructores de las clases derivadas, y no se llamaban.
Historia 2
En una biblioteca de red para el protocolo TCP, al eliminar sesiones, no se llamó al destructor de los descendientes, gestionados a través de una interfaz base común. Esto llevó a un bloqueo masivo de sockets y al agotamiento de los límites de descriptores.
Historia 3
En un sistema embebido en C++, un destructor de clase base mal declarado (no virtual) causó una fuga de memoria para los recursos del sistema de controladores de entrada y salida, y los dispositivos fallaron después de varios ciclos de actualización de controladores.