modificador - polimorfismo puro c++
Anular de forma segura las funciones virtuales de C++ (8)
Algo como la palabra clave de override
C # no es parte de C ++.
En gcc, -Woverloaded-virtual
advierte contra la ocultación de una función virtual de la clase base con una función del mismo nombre pero con una firma suficientemente diferente que no la anule. Sin embargo, no lo protegerá de no anular una función debido a la ortografía incorrecta del nombre de la función en sí.
Tengo una clase base con una función virtual y quiero anular esa función en una clase derivada. ¿Hay alguna manera de hacer que el compilador compruebe si la función que declare en la clase derivada realmente anula una función en la clase base? Me gustaría agregar alguna macro o algo que asegure que no haya declarado accidentalmente una nueva función, en lugar de anular la anterior.
Toma este ejemplo:
class parent {
public:
virtual void handle_event(int something) const {
// boring default code
}
};
class child : public parent {
public:
virtual void handle_event(int something) {
// new exciting code
}
};
int main() {
parent *p = new child();
p->handle_event(1);
}
Aquí se llama a parent::handle_event()
lugar de child::handle_event()
, porque el método del child::handle_event()
la declaración const
y, por lo tanto, declara un nuevo método. Esto también podría ser un error ortográfico en el nombre de la función o una pequeña diferencia en los tipos de parámetros. También puede suceder fácilmente si la interfaz de la clase base cambia y en algún lugar alguna clase derivada no se actualizó para reflejar el cambio.
¿Hay alguna manera de evitar este problema? ¿De alguna manera puedo decirle al compilador o alguna otra herramienta que verifique esto por mí? Cualquier indicador de compilador útil (preferiblemente para g ++)? ¿Cómo se evitan estos problemas?
Desde g ++ 4.7, comprende la nueva palabra clave de override
C ++ 11:
class child : public parent {
public:
// force handle_event to override a existing function in parent
// error out if the function with the correct signature does not exist
void handle_event(int something) override;
};
En MSVC ++ puede usar override
palabra clave
class child : public parent { public: virtual void handle_event(int something) override { // new exciting code } };
override
funciona tanto para el código nativo como CLR en MSVC ++.
En MSVC, puede usar la palabra clave de override
CLR, incluso si no está compilando para CLR.
En g ++, no hay forma directa de aplicar eso en todos los casos; otras personas han dado buenas respuestas sobre cómo detectar las diferencias de firma usando -Woverloaded-virtual
. En una versión futura, alguien podría agregar sintaxis como __attribute__ ((override))
o su equivalente usando la sintaxis de C ++ 0x.
Haga que la función sea abstracta, de modo que las clases derivadas no tengan otra opción que anularla.
@Ray Tu código no es válido.
class parent {
public:
virtual void handle_event(int something) const = 0 {
// boring default code
}
};
Las funciones abstractas no pueden tener cuerpos definidos en línea. Debe ser modificado para convertirse
class parent {
public:
virtual void handle_event(int something) const = 0;
};
void parent::handle_event( int something ) { /* do w/e you want here. */ }
Por lo que yo sé, ¿no puedes hacerlo abstracto?
class parent {
public:
virtual void handle_event(int something) const = 0 {
// boring default code
}
};
Creí leer en www.parashift.com que realmente puedes implementar un método abstracto. Lo cual tiene sentido para mí personalmente, lo único que hace es forzar subclases para implementarlo, nadie dijo nada acerca de que no se le permita tener una implementación en sí misma.
Su compilador puede tener una advertencia que puede generar si una función de clase base se oculta. Si lo hace, habilítalo. Eso atrapará los choques de const y las diferencias en las listas de parámetros. Lamentablemente, esto no descubrirá un error ortográfico.
Por ejemplo, esto es advertencia C4263 en Microsoft Visual C ++.
Sugeriría un ligero cambio en tu lógica. Puede o no funcionar, dependiendo de lo que necesite lograr.
handle_event () aún puede hacer el "código predeterminado aburrido", pero en lugar de ser virtual, en el punto en el que desea que aparezca el "nuevo código emocionante", la clase base llama a un método abstracto (es decir, debe ser reemplazado) eso será provisto por tu clase descendiente.
EDITAR: Y si posteriormente decide que algunas de sus clases descendientes no necesitan proporcionar "nuevo código interesante", puede cambiar el resumen a virtual y proporcionar una implementación de clase base vacía de esa funcionalidad "insertada".