- Sí, son iguales. 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 fuera virtual en una clase base. En> = C ++ 11 se puede utilizar
final
para evitar que se anule en clases derivadas, pero eso no impide que sea virtual.
- Sí, se puede omitir un destructor en una clase derivada si no tiene nada que hacer. Y no importa si es virtual o no.
- Lo omitiría si fuera posible. Y siempre uso la
virtual
palabra clave nuevamente para funciones virtuales en clases derivadas por razones de claridad. La gente no debería tener que subir hasta arriba en la jerarquía de herencia para darse cuenta de 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 los constructores copiar y mover y los operadores de asignación si lo desea ya que el compilador ya no los colocará por usted.
Como 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 ese predeterminado es una función en línea.
Las funciones en línea exponen potencialmente más de su programa a cambios en otras partes de su programa y hacen que la compatibilidad binaria para bibliotecas compartidas sea complicada. Además, el aumento del acoplamiento puede resultar en una gran recompilación frente a ciertos tipos de cambios. Por ejemplo, si decide que realmente quiere una implementación para su destructor virtual, entonces cada fragmento de código que lo llamó deberá ser recompilado. Mientras que si lo hubiera declarado en el cuerpo de la clase y luego lo hubiera definido vacío en un .cpp
archivo, estaría bien cambiarlo sin volver a compilar.
Mi elección personal aún sería omitirlo cuando sea posible. En mi opinión, satura el código y el compilador a veces puede hacer cosas un poco más eficientes con una implementación predeterminada sobre una vacía. Pero hay limitaciones en las que puede encontrarse que hacen que sea una mala elección.
fuente
final
.Una función miembro virtual hará implícitamente virtual cualquier sobrecarga de esta función.
Entonces, el virtual en 1) es "opcional", el destructor de la clase base al ser virtual hace que todos los destructores secundarios también sean virtuales.
fuente
1 / Sí 2 / Sí, será generado por el compilador 3 / La elección entre declararlo virtual o no debe seguir su convención para miembros virtuales anulados - En mi humilde opinión, hay buenos argumentos en ambos sentidos, simplemente elija uno y sígalo.
Lo omitiría si es posible, pero hay una cosa que puede incitarte a declararlo: si usas el compilador generado, está implícitamente en línea. Hay ocasiones en las que desea evitar los miembros en línea (bibliotecas dinámicas, por ejemplo).
fuente
Las funciones virtuales se anulan implícitamente. Cuando el método de una clase secundaria coincide con la firma del método de la función virtual de una clase base, se anula. Esto es fácil de confundir y posiblemente romper durante la refactorización, por lo que existen
override
yfinal
palabras clave desde C ++ 11 para marcar este comportamiento explícitamente. Hay una advertencia correspondiente que prohíbe el comportamiento silencioso, por ejemplo-Wsuggest-override
en GCC.Hay una pregunta relacionada para
override
yfinal
palabras clave en SO: ¿Es la palabra clave 'anular' solo una verificación para un método virtual anulado? .Y la documentación en la referencia cpp https://en.cppreference.com/w/cpp/language/override
El uso de
override
palabras clave con los destructores sigue siendo un tema de debate. Por ejemplo, consulte la discusión en esta pregunta relacionada con SO: anulación predeterminada del destructor virtual El problema es que la semántica del destructor virtual es diferente a las funciones normales. Los destructores están encadenados, por lo que todos los destructores de clases base se llaman después del hijo uno. Sin embargo, en el caso de un método regular, las implementaciones básicas del método reemplazado no se llaman por defecto. Se pueden llamar manualmente cuando sea necesario.fuente