Anular funciones virtuales C++ de forma segura


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 declaré 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 declaré accidentalmente una nueva función, en lugar de anular la antigua.

Tomemos 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 parent::handle_event() en lugar de child::handle_event(), porque el método child pierde la declaración const 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 al compilador o a alguna otra herramienta que lo compruebe por mí? ¿Algún indicador de compilador útil (preferiblemente para g++)? ¿Cómo evitar estos problemas?

Author: sth, 2009-01-31

8 answers

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;
};
 81
Author: Gunther Piez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-27 13:13:52

Algo como la palabra clave de C#override 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 suficientemente diferente que no la anule. Sin embargo, no lo protegerá contra el fallo al anular una función debido a una mala ortografía del nombre de la función en sí.

 20
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-30 23:31:01

Por lo que sé, ¿no puedes simplemente hacerlo abstracto?

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

Pensé que seguía leyendo www.parashift.com que realmente se puede 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 sobre que no se le permitiera tener una implementación en sí.

 16
Author: Ray Hidayat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-30 23:32:24

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

En g++, no hay una 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 sintaxis como __attribute__ ((override)) o su equivalente usando la sintaxis de C++0x.

 11
Author: Doug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-31 00:26:23

En MSVC++ puedes usar la palabra clave override

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

override funciona tanto para código nativo como CLR en MSVC++.

 9
Author: bobobobo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 18:55:23

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

@ 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 en

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

void parent::handle_event( int something ) { /* do w/e you want here. */ }
 5
Author: Tanveer Badar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-31 07:56:38

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 el "código predeterminado aburrido", pero en lugar de ser virtual, en el punto en el que desea que haga el "nuevo código emocionante", haga que la clase base llame a un método abstracto (es decir, debe ser sobrescrito) que será suministrado por su clase descendiente.

EDITAR: Y si más tarde decide que algunas de sus clases descendientes hacen no necesidad de proporcionar " nuevo código emocionante "a continuación, puede cambiar el resumen a virtual y proporcionar una implementación de clase base vacía de esa funcionalidad" insertado".

 3
Author: JMD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-30 23:12:45

Su compilador puede tener una advertencia que puede generar si una función de clase base se oculta. Si lo hace, habilítelo. Eso atrapará los choques de const y las diferencias en las listas de parámetros. Desafortunadamente esto no descubrirá un error de ortografía.

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

 2
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-30 23:17:45