El propósito de virtual destructor (es decir, el propósito de hacer un destructor virtual) es facilitar la eliminación polimórfica de objetos a través de delete-expresión. Si su diseño no requiere la eliminación polimórfica de objetos, no necesita destructores virtuales. En referencia a su ejemplo, si alguna vez tiene que eliminar un objeto del tipo B
mediante un puntero de tipo A *
(eliminación polimórfica), necesitará un destructor virtual tan alto en la jerarquía como A
. Así es como se ve desde un punto de vista formal.
(Nota, por cierto, como dijo Neil, que lo importante es la forma de crear/borrar sus objetos de clase, no cómo las clases gestionar su memoria interna.)
En cuanto a las buenas prácticas de programación ... depende en su intento y su diseño al final.Si sus clases no están diseñadas para ser polimórficas en absoluto (sin métodos virtuales), entonces no necesita destructores virtuales. Si su clase es polimórfica (tiene al menos un método virtual), entonces hacer que el destructor sea virtual "por las dudas" podría ser una muy buena idea, y en este caso lleva consigo prácticamente ninguna penalización de rendimiento/memoria.
Esto último generalmente se expresa como una guía de buenas prácticas bastante conocida: si su clase tiene al menos un método virtual, también haga que el destructor sea virtual. Aunque desde el punto de vista formal, un destructor virtual podría no ser realmente necesario allí, sigue siendo una buena guía para seguir.
Las clases que no tienen recursos pero pueden formar jerarquías polimórficas siempre deben definir destructores virtuales vacíos, excepto que es perfectamente suficiente para definir un destructor virtual explícito vacío (e incluso puro) en la base misma de la jerarquía. Todos los demás destructores se volverán virtuales automáticamente, incluso si el compilador los define implícitamente. Es decir. no tiene que definir explícitamente un destructor vacío en cada clase. Solo la base es suficiente.
@ALL He ejecutado el ejemplo de código anterior con valgrind, al crear el objeto de clase derivado dinámicamente (es decir, "A * a = new B; delete a;") Observé que no hay pérdida de memoria. Incluso el destructor de clase derivado no se invoca. ¿Por qué no pérdida de memoria? – BSalunke