entre diferencias c++ c++11 c++14

c++ - diferencias - anulación predeterminada del destructor virtual



diferencias entre c++ y c++ 11 (6)

Todo el mundo sabe que el destructor de la clase base generalmente tiene que ser virtual. Pero ¿qué pasa con el destructor de la clase derivada? En C ++ 11 tenemos la palabra clave "anular" y la capacidad de usar el destructor predeterminado de manera explícita.

struct Parent { std::string a; virtual ~Parent() { } }; struct Child: public Parent { std::string b; ~Child() override = default; };

¿Es correcto usar ambas palabras clave "anular" y "= predeterminado" en el destructor de la clase secundaria? ¿El compilador generará el destructor virtual correcto en este caso?

En caso afirmativo, ¿podemos pensar que es un buen estilo de codificación, y siempre debemos declarar los destructores de las clases derivadas de esta manera para asegurarnos de que los destructores de la clase base sean virtuales?


¿Es correcto usar ambas palabras clave "anular" y "= predeterminado" en el destructor de la clase secundaria? ¿El compilador generará el destructor virtual correcto en este caso?

Si es correcto. En cualquier compilador sano, si el código se compila sin errores, esta definición del destructor será un no-op: su ausencia no debe cambiar el comportamiento del código.

¿Podemos pensar que es un buen estilo de codificación?

Es una cuestión de preferencia. Para mí, solo tiene sentido si el tipo de clase base es una plantilla: impondrá un requisito en la clase base para tener un destructor virtual, entonces. De lo contrario, cuando el tipo de base sea fijo, consideraría que dicho código es ruido. No es como si la clase base cambiara mágicamente. Pero si tiene compañeros de equipo sin rumbo que les gusta cambiar las cosas sin verificar el código que depende de lo que posiblemente estén rompiendo, es mejor dejar la definición del destructor como una capa adicional de protección.


Aunque los destructores no se heredan, está claro en el Estándar que los destructores virtuales de las clases derivadas anulan a los destructores de las clases base.

Desde el estándar de C ++ (10.3 funciones virtuales)

6 Aunque los destructores no se heredan, un destructor en una clase derivada anula un destructor de clase base declarado virtual; ver 12.4 y 12.5.

Por otro lado también está escrito (9.2 Miembro de la clase)

8 Un virt-speci fi er-seq contendrá como máximo uno de cada virt-speci fi er. Un virt-speci fi er-seq aparecerá solo en la declaración de una función miembro virtual (10.3).

Aunque los destructores se denominan funciones miembro especiales, también son funciones miembro.

Estoy seguro de que el estándar de C ++ debería editarse de tal manera que no fuera ambiguo si un destructor puede tener una override virt-specifier. En la actualidad no está claro.


Creo que "anular" es algo engañoso en el destructor. Cuando reemplaza la función virtual, la reemplaza. Los destructores están encadenados, por lo que no se puede anular literalmente el destructor


Hay (al menos) una razón para usar la override aquí: usted se asegura de que el destructor de la clase base sea siempre virtual. Será un error de compilación si el destructor de la clase derivada cree que está anulando algo, pero no hay nada que anular. También te da un lugar conveniente para dejar la documentación generada, si lo haces.

Por otro lado, puedo pensar en dos razones para no hacer esto:

  • Es un poco raro y al revés para la clase derivada imponer el comportamiento de la clase base.
  • Si define un destructor en el encabezado (o si lo hace en línea), introduce la posibilidad de errores de compilación impares. Digamos que su clase se ve así:

    struct derived { struct impl; std::unique_ptr<derived::impl> m_impl; ~derived() override = default; };

    Probablemente obtendrá un error de compilador porque el destructor (que está en línea con la clase aquí) buscará el destructor para la clase incompleta, derived::impl .

    Esta es mi manera de decir que cada línea de código puede convertirse en una responsabilidad, y tal vez sea mejor omitir algo si no hace nada funcionalmente. Si realmente necesita imponer un destructor virtual en la clase base de la clase principal, alguien sugirió usar static_assert en concierto con std::has_virtual_destructor , que producirá resultados más consistentes, IMHO.


La referencia de CPP dice que la override se asegura de que la función sea virtual y que de hecho anula una función virtual. Así que la palabra clave de override se aseguraría de que el destructor sea virtual.

Si especifica override pero no = default , obtendrá un error de vinculador.

No necesitas hacer nada. Dejando al Child dtor indefinido funciona bien:

#include <iostream> struct Notify { ~Notify() { std::cout << "dtor" << std::endl; } }; struct Parent { std::string a; virtual ~Parent() {} }; struct Child : public Parent { std::string b; Notify n; }; int main(int argc, char **argv) { Parent *p = new Child(); delete p; }

Eso dará salida a dtor . Sin embargo, si elimina el virtual en Parent::~Parent , no generará nada porque se trata de un comportamiento indefinido, como se señala en los comentarios.

Buen estilo sería no mencionar Child::~Child en absoluto. Si no puede confiar en que la clase base la declaró virtual, su sugerencia con override y = default funcionará; Espero que haya mejores maneras de garantizar que, en lugar de ensuciar su código con esas declaraciones de destructores.


override no es más que una red de seguridad. El destructor de la clase secundaria siempre será virtual si el destructor de la clase base es virtual, sin importar cómo se declare, o no se declare en absoluto (es decir, usar una implícitamente declarada).