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
override
palabra clave.La 'virtualidad' de una función se propaga implícitamente, sin embargo, al menos un compilador que uso generará una advertencia si la
virtual
palabra 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
virtual
palabra 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
virtual
palabra 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
virtual
no 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
virtual
palabra 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
float
como 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
virtual
en la clase derivada o lo omite.Pero debe mirar la clase base para obtener esta información. Por lo tanto, recomendaría agregar la
virtual
palabra 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
typedef
B 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
virtual
palabra clave debe agregarse a las funciones de una clase base para hacerlas reemplazables. En su ejemplo,struct A
es la clase base.virtual
no 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 ponervirtual
allí.Aquí
C
hereda deB
, porB
lo que no es la clase base (también es una clase derivada), yC
es la clase derivada. El diagrama de herencia se ve así:Por lo tanto, debe colocar las
virtual
funciones delante de las clases base potenciales que pueden tener hijos.virtual
permite que sus hijos anulen sus funciones. No hay nada de malo en poner lasvirtual
funciones 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
virtual
delante 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