2010-02-04 9 views
65

Si tengo una clase base con un destructor virtual. Tiene una clase derivada para declarar un destructor virtual también?¿Se heredan los destructores virtuales?

class base { 
public: 
    virtual ~base() {} 
}; 

class derived : base { 
public: 
    virtual ~derived() {} // 1) 
    ~derived() {} // 2) 
}; 

preguntas de hormigón:

  1. es 1) y 2) de la misma? ¿Es 2) automáticamente virtual debido a su base o "detiene" la virtualidad?
  2. ¿Se puede omitir el destructor derivado si no tiene nada que hacer?
  3. ¿Cuál es la mejor práctica para declarar el destructor derivado? ¿Declararlo virtual, no virtual u omitirlo si es posible?

Respuesta

82
  1. Sí, son lo mismo. La clase derivada que no declara algo virtual no impide que sea virtual. De hecho, no hay forma de evitar que un método (destructor incluido) sea virtual en una clase derivada si fue virtual en una clase base. En> = C++ 11 puede usar final para evitar que se anule en clases derivadas, pero eso no impide que sea virtual.
  2. Sí, un destructor en una clase derivada se puede omitir si no tiene nada que ver. Y no importa si es virtual o no.
  3. Lo omitiría si fuera posible. Y siempre uso la palabra clave virtual nuevamente para funciones virtuales en clases derivadas por razones de claridad. La gente no debería tener que recorrer todo el camino de la jerarquía de herencia para descubrir que una función es virtual. Además, si su clase se puede copiar o mover sin tener que declarar su propia copia o mover constructores, declarar un destructor de cualquier tipo (incluso si lo define como default) lo obligará a declarar la copia y mover los constructores y operadores de asignación si los quiero porque el compilador ya no los pondrá por ti.

Como un pequeño punto para el elemento 3. Se ha señalado en los comentarios que si un destructor no se declara el compilador genera uno predeterminado (que sigue siendo virtual). Y esa predeterminada es una función en línea.

Las funciones en línea pueden exponer más de su programa a cambios en otras partes de su programa y hacer que la compatibilidad binaria para las bibliotecas compartidas sea complicada. Además, el aumento de acoplamiento puede dar lugar a una gran cantidad de recompilación frente a ciertos tipos de cambios. Por ejemplo, si decide que realmente desea una implementación para su destructor virtual, entonces cada parte del código que lo llamó tendrá que ser recompilado. Mientras que si lo hubiera declarado en el cuerpo de la clase y luego lo haya definido vacío en un archivo .cpp, estaría bien cambiarlo sin volver a compilar.

Mi elección personal sería omitirla cuando sea posible. En mi opinión, complica el código, y el compilador a veces puede hacer cosas ligeramente más eficientes con una implementación predeterminada que con una vacía. Pero existen restricciones en las que puede estar inmerso que hacen que esa sea una mala elección.

+0

Su última frase probablemente debería decir "no debería" en lugar de "debería". –

+0

@Chris Lutz, estoy delante de ti en eso. Ha sido editado en sumisión ahora. :-) – Omnifarious

+1

No estoy de acuerdo con la parte 'omit'. No cuesta mucho declararlo en el encabezado y definirlo (cuerpo vacío) en la fuente. Si lo hace, siempre puede regresar y agregar algunos pasos (¿inicio de sesión?) Sin forzar a sus clientes a recompilar. –

1

Una función miembro virtual hará implícitamente cualquier sobrecarga de esta función virtual.

Por lo tanto, el virtual en 1) es "opcional", el destructor de la clase base que es virtual hace que todos los destructores secundarios sean virtuales también.

1
  1. El destructor es automáticamente virtual, como con todos los métodos. No se puede evitar que un método sea virtual en C++ (si ya se ha declarado virtual, es decir, es decir,no hay un equivalente de 'final' en Java)
  2. Sí, se puede omitir.
  3. Declararía un destructor virtual si pretendo que se subclasse esta clase, no importa si está subclasando otra clase o no, también prefiero seguir declarando métodos virtuales, aunque no sea necesario. Esto mantendrá las subclases funcionando, en caso de que alguna vez decida eliminar la herencia. Pero supongo que esto es solo una cuestión de estilo.
+0

Los destructores no son automáticamente virtuales, ni tampoco otras funciones miembro. –

+1

@Neil; por supuesto que no, me refería a _the_ destructor en el ejemplo (es decir, donde la clase base tiene una virtual), no destructores en general. Y esto es cierto para todos los métodos, no solo para los destructores. – falstro

0

1/Sí 2/Sí, va a ser generado por el compilador 3/La elección entre declarar que virtual o no debe seguir su convención para los miembros virtuales overriden - En mi humilde opinión, hay buenos argumentos tanto camino , solo elige uno y síguelo.

Lo omitiría si fuera posible, pero hay una cosa que puede incitarlo a declararlo: si utiliza el compilador generado, está implícitamente en línea. Hay momentos en los que desea evitar miembros en línea (bibliotecas dinámicas, por ejemplo).

Cuestiones relacionadas