Pregunta

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 x no utilizado. ¿Hay alguna otra forma en que debería haber implementado la función virtual? Lo he reescrito así:

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

También tengo el problema de que si no tengo cuidado, la subclase que hago puede implementar la función incorrecta y luego no me doy cuenta debido a la sobrecarga: por ejemplo,

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 clase base porque implementé la función derivada con un " int y " param pero no hay advertencia sobre esto. ¿Son estos escollos comunes en C ++ o he entendido mal las funciones virtuales?

¿Fue útil?

Solución

Ignorando los problemas de diseño que puede evitar 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 incorrecto al intentar anular la función virtual es algo de lo que debe tener cuidado en C ++. Los lenguajes como C # evitan esto con la palabra clave 'anular'.

Otros consejos

Definimos una 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 ha olvidado de x: está intencionalmente ignorándolo.

¿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 generar una excepción

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 , entonces mi consejo sería hacer una función virtual pura y dejarla en manos de la clase derivada para proporcionar una implementación. Las clases derivadas que no permiten que se invoque el método pueden generar una excepción para garantizar que no se utilice por error.

Además de simplemente omitir el nombre de la variable, en muchos compiladores puede decirle al compilador que sabe que no se utiliza y que se CIERRA al hacer esto

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

Esto es algo común en mi código. Por ejemplo, tengo clases que están diseñadas para operación de un solo subproceso y multi-subproceso. 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 implica, pero la clase de subprocesos múltiples sí.

Tengo una función de fábrica que crea la clase derivada apropiada y luego devuelve 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.

No es una mala práctica y es un idioma común para especificar partes de una clase que son opcionales de 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 muy 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) {}
};

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

Base *b = &d;

Funcionará igual de bien, dynamic_cast<> en su lugar se debe usar cuando se baja, es decir, desde la base hasta la 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.

También, como han dicho otros, los nombres de variables son opcionales en declaraciones de funciones como esta.

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 ++ al más alto nivel de todos modos).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top