Con la definición de estructura dada a continuación ...
struct A {
virtual void hello() = 0;
};
Enfoque n. ° 1:
struct B : public A {
virtual void hello() { ... }
};
Enfoque # 2:
struct B : public A {
void hello() { ... }
};
¿Hay alguna diferencia entre estas dos formas de anular la función hello?
c++
overriding
virtual-functions
Anarki
fuente
fuente

Respuestas:
Son exactamente lo mismo. No hay diferencia entre ellos aparte de que el primer enfoque requiere más tipeo y es potencialmente más claro.
fuente
overridepalabra clave.La 'virtualidad' de una función se propaga implícitamente, sin embargo, al menos un compilador que uso generará una advertencia si la
virtualpalabra clave no se usa explícitamente, por lo que es posible que desee usarla solo para mantener el compilador en silencio.Desde un punto de vista puramente estilístico, incluir la
virtualpalabra clave claramente 'anuncia' el hecho al usuario de que la función es virtual. Esto será importante para cualquier persona que subclasifique B sin tener que verificar la definición de A. Para jerarquías de clase profundas, esto se vuelve especialmente importante.fuente
La
virtualpalabra clave no es necesaria en la clase derivada. Aquí está la documentación de respaldo, del C ++ Draft Standard (N3337) (el énfasis es mío):fuente
No, el
virtualno se requiere palabra clave en la anulación de la función virtual de las clases derivadas. Pero vale la pena mencionar una trampa relacionada: una falla al anular una función virtual.El error de anulación se produce si tiene la intención de anular una función virtual en una clase derivada, pero comete un error en la firma para que declare una función virtual nueva y diferente. Esta función puede ser una sobrecarga de la función de clase base, o puede diferir en nombre. Si usa o no el
virtualpalabra clave en la declaración de función de clase derivada, el compilador no podrá decir que tenía la intención de anular una función de una clase base.Sin embargo, esta trampa es abordada afortunadamente por la función de lenguaje de anulación explícita de C ++ 11 , que permite que el código fuente especifique claramente que una función miembro tiene la intención de anular una función de clase base:
El compilador emitirá un error en tiempo de compilación y el error de programación será inmediatamente obvio (quizás la función en Derivado debería haber tomado a
floatcomo argumento).Consulte WP: C ++ 11 .
fuente
Agregar la palabra clave "virtual" es una buena práctica ya que mejora la legibilidad, pero no es necesario. Las funciones declaradas virtuales en la clase base y tener la misma firma en las clases derivadas se consideran "virtuales" de forma predeterminada.
fuente
No hay diferencia para el compilador, cuando escribe el
virtualen la clase derivada o lo omite.Pero debe mirar la clase base para obtener esta información. Por lo tanto, recomendaría agregar la
virtualpalabra clave también en la clase derivada, si desea mostrarle al ser humano que esta función es virtual.fuente
Hay una diferencia considerable cuando tiene plantillas y comienza a tomar clases básicas como parámetros de plantilla:
La parte divertida es que ahora puede definir funciones de interfaz y no de interfaz más adelante para definir clases. Eso es útil para interfuncionar interfaces entre bibliotecas (no confíe en esto como un proceso de diseño estándar de una sola biblioteca). No le cuesta nada permitir esto para todas sus clases; incluso podría
typedefB a algo si lo desea.Tenga en cuenta que, si hace esto, es posible que también desee declarar copiar / mover constructores como plantillas: permitir construir desde diferentes interfaces le permite 'lanzar' entre diferentes
B<>tipos.Es cuestionable si debe agregar soporte para
const A&int_hello(). La razón habitual para esta reescritura es alejarse de la especialización basada en herencia a una basada en plantilla, principalmente por razones de rendimiento. Si continúa admitiendo la interfaz anterior, difícilmente podrá detectar (o disuadir) el uso anterior.fuente
La
virtualpalabra clave debe agregarse a las funciones de una clase base para hacerlas reemplazables. En su ejemplo,struct Aes la clase base.virtualno significa nada para usar esas funciones en una clase derivada. Sin embargo, si desea que su clase derivada también sea una clase base en sí misma, y desea que esa función sea reemplazable, entonces tendría que ponervirtualallí.Aquí
Chereda deB, porBlo que no es la clase base (también es una clase derivada), yCes la clase derivada. El diagrama de herencia se ve así:Por lo tanto, debe colocar las
virtualfunciones delante de las clases base potenciales que pueden tener hijos.virtualpermite que sus hijos anulen sus funciones. No hay nada de malo en poner lasvirtualfunciones delante de las clases derivadas, pero no es obligatorio. Sin embargo, se recomienda, porque si alguien quisiera heredar de su clase derivada, no estaría contento de que la anulación del método no funcione como se esperaba.Así que ponga
virtualdelante de las funciones en todas las clases involucradas en la herencia, a menos que sepa con certeza que la clase no tendrá hijos que necesiten anular las funciones de la clase base. Es una buena práctica.fuente
Ciertamente incluiré la palabra clave virtual para la clase secundaria, porque
fuente