virtuales que puro puras polimorfismo objeto modificador herencia funciones c++ polymorphism

que - polimorfismo puro c++



¿Las funciones virtuales no puras con parámetros son una mala práctica? (10)

¿Por qué definirlo en la clase base? Si la clase base no va a usar el método, simplemente defínalo como un método virtual en su clase derivada.

O la implementación predeterminada podría arrojar una excepción

Tengo una clase base con una función virtual opcional

class Base { virtual void OnlyImplementThisSometimes(int x) {} };

Cuando compilo esto, recibo una advertencia sobre el parámetro no utilizado. ¿Hay alguna otra forma en que debería haber implementado la función virtual? Lo he reescrito de esta manera:

class Base { virtual void OnlyImplementThisSometimes(int x) { x = 0; } };

También tengo el problema de que si no soy cuidadoso, la subclase que realizo puede implementar la función incorrecta y luego no lo noto debido a una sobrecarga: por ej.

class Derived : public Base { void OnlyImplementThisSometimes(int x, int y) { // some code } }; Derived d; Base *b = dynamic_cast<Base *>(&d); b->OnlyImplementThisSometimes(x); // calls the method in the base class

Se llamó al método de la clase base porque implementé la función derivada con un parámetro "int y" pero no hay ninguna advertencia al respecto. ¿Son estos errores comunes en C ++ o he entendido mal las funciones virtuales?


Además de simplemente omitir el nombre de la variable, en muchos compiladores puede decirle al compilador que está consciente de que no está siendo utilizado y SHUTUP haciendo esto

int func(int x) { (void) x; }


Definimos un macro _unused como:

#define _unused(x) ((void)x)

Luego defina la función como:

virtual void OnlyImplementThisSometimes(int x) { _unused( x );}

Esto no solo evita que el compilador se queje, sino que hace que sea obvio para cualquiera que mantenga el código que no haya olvidado x, usted lo ignora intencionalmente .


Esto es algo común en mi código. Por ejemplo, tengo clases que están diseñadas para operación de subproceso único y multiproceso. Hay muchas rutinas y datos comunes. Puse todo eso en la clase base (que también tiene un par de virtuales puros).

Implemento dos funciones virtuales vacías en la clase base: Init () y Cleanup (). La clase derivada de un solo subproceso no los implementa, pero sí el subproceso múltiple.

Tengo una función de fábrica crear la clase derivada apropiada y luego devolver un puntero. El código del cliente solo conoce el tipo de clase base y llama a Init () y Cleanup (). Ambos escenarios hacen lo correcto.

Por supuesto, puede haber otras buenas sugerencias sobre cómo hacer esto, pero este modismo funciona bien para gran parte de mi código.


Haciendo caso omiso de los problemas de diseño que puede obtener con la advertencia del compilador sobre una variable no utilizada al omitir el nombre de la variable, por ejemplo:

virtual void OnlyImplementThisSometimes(int ) { }

Implementar erróneamente la firma del método equivocado al intentar anular la función virtual es algo de lo que hay que tener cuidado en C ++. Los lenguajes como C # solucionan esto con la palabra clave ''anular''.


La respuesta más simple a esto se muestra a continuación:

class Base { virtual void OnlyImplementThisSometimes(int x) { x;} };

Una simple referencia a la variable que no hace absolutamente nada eliminará todas las advertencias (de VC ++ en el nivel más alto de todos modos).


No es una mala práctica y es una expresión común para especificar partes de una clase que son opcionales para implementar.

Actualmente lo estoy usando para un sistema de entrada de usuario, porque sería tedioso para un usuario de esa clase implementar cada método, incluso si es probable que no lo use de todos modos.

class mouse_listener{ public: virtual ~mouse_listener() {} virtual void button_down(mouse_button a_Button) {} virtual void button_up(mouse_button a_Button) {} virtual void scroll_wheel(mouse_scroll a_Scroll) {} virtual void mouse_move_abs(math::point a_Position) {} virtual void mouse_move_rel(math::point a_Position) {} };


Si proporciona una implementación predeterminada de una función virtual, debería ser una implementación correcta para todas las clases derivadas que no anulan esa función. Si no puede proporcionar una implementación correcta , mi consejo sería hacer una función virtual pura y dejarla a la clase derivada para proporcionar una implementación. Las clases derivadas que no permiten que se llame al método pueden lanzar una excepción para garantizar que no se use por error.


Por cierto, si conoces tu clase base, nunca hay necesidad de hacer difusiones dinámicas, es decir, de derivado a base.

Base *b = &d;

Lo hará igual de bien, dynamic_cast<> debería utilizarse en su lugar cuando se realiza el down-cast, es decir, desde base hasta derivada:

if((Derived *d = dynamic_cast<Derived *>(b)) != 0) { // use d }

(Y por supuesto en el caso de down-cast, static_cast<> generalmente también funcionará).


Prueba esto:

class Base { virtual void OnlyImplementThisSometimes(int x) = 0; };

Ha pasado un tiempo desde que hice cosas así, pero creo que así es como declaras una función virtual.

Además, como otros han dicho, los nombres de variables son opcionales en declaraciones de funciones como esta.