Pregunta

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 verifique si la función que declaré en la clase derivada realmente anula una función en la clase base?Me gustaría agregar alguna macro o algo que garantice que no declaré accidentalmente una nueva función, en lugar de anular la anterior.

Tome 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í parent::handle_event() se llama en lugar de child::handle_event(), porque el método del niño omite la const declaración y por lo tanto declara un nuevo método.Esto también podría ser un error tipográfico en el nombre de la función o alguna diferencia menor 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? ¿Puedo decirle de alguna manera al compilador o a alguna otra herramienta que verifique esto por mí?¿Alguna característica útil del compilador (preferiblemente para g++)?¿Cómo se evitan estos problemas?

¿Fue útil?

Solución

Desde g ++ 4.7 entiende la nueva palabra clave C ++ 11 override:

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;
};

Otros consejos

Algo así como la palabra clave override de C # no es parte de C ++.

En gcc, -Woverloaded-virtual advierte contra ocultar una función virtual de clase base con una función del mismo nombre pero con una firma lo suficientemente diferente como para no anularla. Sin embargo, no lo protegerá de no anular una función debido a la falta de ortografía del nombre de la función.

Hasta donde yo sé, ¿no puedes simplemente hacerlo abstracto?

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

Pensé que leí en www.parashift.com que realmente puedes implementar un método abstracto. Lo que tiene sentido para mí personalmente, lo único que hace es forzar a las subclases a implementarlo, nadie dijo nada acerca de que no se le permitiera tener una implementación en sí.

En MSVC, puede usar la palabra clave CLR override incluso si no está compilando para CLR.

En g ++, no hay forma directa de hacer cumplir eso en todos los casos; otras personas han dado buenas respuestas sobre cómo detectar diferencias de firma usando -Woverloaded-virtual. En una versión futura, alguien podría agregar una sintaxis como __attribute__ ((override)) o su equivalente usando la sintaxis C ++ 0x.

En MSVC ++ puede usar palabra clave override

    class child : public parent {
    public:
      virtual void handle_event(int something) override {
        // new exciting code
      }
    };

<=> funciona tanto para el código nativo como para el código CLR en MSVC ++.

Haga que la función sea abstracta, de modo que las clases derivadas no tengan otra opción que anularla.

@Ray Su 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 modificarse 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. */ }

Sugeriría un ligero cambio en su lógica. Puede o no funcionar, dependiendo de lo que necesite lograr.

handle_event () todavía puede hacer " código predeterminado aburrido " pero en lugar de ser virtual, en el punto donde desea que haga el " nuevo código emocionante " haga que la clase base llame a un método abstracto (es decir, debe ser reemplazado) método que será proporcionado por su clase descendiente.

EDITAR: Y si luego decide que algunas de sus clases descendientes no necesitan proporcionar " nuevo código emocionante " entonces puede cambiar el resumen a virtual y proporcionar una implementación de clase base vacía de ese " insertado " funcionalidad.

Su compilador puede tener una advertencia que puede generar si una función de clase base se oculta. Si lo hace, habilítelo. Eso detectará choques constantes y diferencias en las listas de parámetros. Lamentablemente, esto no descubrirá un error ortográfico.

Por ejemplo, esta es la advertencia C4263 en Microsoft Visual C ++.

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