¿La palabra clave 'anular' es solo una verificación de un método virtual anulado?

226

Por lo que entiendo, la introducción de overridepalabras clave en C ++ 11 no es más que una verificación para asegurarse de que la función que se implementa es la función overridede una virtualfunción en la clase base.

¿Es asi?

aiao
fuente
50
Sí.
R. Martinho Fernandes
13
Sin embargo, no es una verificación doble. Es el único cheque.
Nikos C.
13
oye, anular NO es una palabra clave, es una especie de azúcar gramatical. int override = 42; // OK
KAlO2
2
Además, mejora la legibilidad explicando que la función declarada se
anula
55
Entonces, eh ... ¿Cuándo será C ++ 11 lo suficientemente estándar como para que empiecen a enseñar cosas como esta en mi local de 4 años? ¿Cuándo lo sabrán?
Cinch

Respuestas:

263

Esa es de hecho la idea. El punto es que usted es explícito sobre lo que quiere decir, de modo que se pueda diagnosticar un error silencioso:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

El código anterior se compila, pero no es lo que debiste haber querido decir (ten en cuenta lo que falta const). Si dijiste en su lugar, virtual int foo() overrideobtendrías un error del compilador de que tu función no anula nada.

Kerrek SB
fuente
74
+1: Aunque, desafortunadamente, es un poco raro cuando la gente sugiere que la nueva overridefunción "arregla" esto; debes recordar usarlo, tal como deberías haber recordado escribir el const;)
Carreras de ligereza en órbita el
Me acabo de dar cuenta de que explicitlas definiciones de clase no llegaron a C ++ 11. Huh
aschepler
1
@aschepler ¿Y qué haría una explicitdefinición de clase? Nunca he oído hablar de eso en absoluto.
Christian Rau
18
@LightnessRacesinOrbit: Sí, no es infalible; sin embargo, recordar una regla general (de escribir locamente overridecuando uno tiene la intención de hacerlo) es más probable que recordar casos de esquina, es decir, no hay generalidad en copiar funciones de diferentes prototipos, solo irregularidades como faltar consto escribir en charlugar de int, etc.
legends2k
1
@ Light, el mejor caso de uso del overrideespecificador se menciona en esta respuesta , que es más futurista que inmediato. La respuesta sugiere que, mantenga overrideel virtualmétodo. En el futuro, cuando un error cambia la firma, sus patadas utilidad en.
iammilind
35

Cita de Wikipedia:

El identificador especial de anulación significa que el compilador verificará la (s) clase (s) base (s) para ver si hay una función virtual con esta firma exacta. Y si no lo hay, el compilador generará un error.

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

Editar (intentando mejorar un poco la respuesta):

Declarar un método como "anulación" significa que ese método está destinado a reescribir un método (virtual) en la clase base. El método de anulación debe tener la misma firma (al menos para los parámetros de entrada) que el método que pretende reescribir.

¿Por qué es esto necesario? Bueno, se evitan los siguientes dos casos de error comunes:

  1. uno escribe mal un tipo en el nuevo método. El compilador, sin saber que tiene la intención de escribir un método anterior, simplemente lo agrega a la clase como un nuevo método. El problema es que el método anterior todavía está allí, el nuevo se agrega solo como una sobrecarga. En este caso, todas las llamadas al método anterior funcionarán igual que antes, sin ningún cambio en el comportamiento (que habría sido el propósito de la reescritura).

  2. uno olvida declarar el método en la superclase como "virtual", pero aún intenta reescribirlo en una subclase. Si bien esto aparentemente será aceptado, el comportamiento no será exactamente como se esperaba: el método no es virtual, por lo que el acceso a través de punteros hacia la superclase terminará llamando al método antiguo (superclase ') en lugar del método nuevo (subclase').

Agregar "anulación" claramente desambigua esto: a través de esto, uno le está diciendo al compilador que tres cosas están esperando:

  1. hay un método con el mismo nombre en la superclase
  2. Este método en la superclase se declara como "virtual" (es decir, destinado a ser reescrito)
  3. el método en la superclase tiene la misma firma (input *) que el método en la subclase (el método de reescritura)

Si alguno de estos es falso, entonces se señala un error.

* nota: el parámetro de salida es a veces de tipo diferente, pero relacionado. Lea sobre las transformaciones covariantes y contravariantes si está interesado.

usuario1284631
fuente
31

La " anulación " encontrada es útil cuando alguien actualizó la firma del método virtual de la clase base, como agregar un parámetro opcional, pero olvidó actualizar la firma del método de la clase derivada. En ese caso, los métodos entre la base y la clase derivada ya no son una relación polimórfica. Sin la declaración de anulación, es difícil descubrir este tipo de error.

usuario3792211
fuente
1
+1. Aunque overridees una excelente manera de descubrir tales problemas, una buena cobertura de pruebas unitarias también debería ayudar.
Desilusionado el
1
Eso es exactamente por qué estoy tan entusiasmado con ese nuevo especificador. El único problema es que esta característica ya debe aplicarse para evitar errores causados ​​por cambios en las clases base. ;-)
Wolf
2

C ++ 17 borrador estándar

Después de repasar todos los overrideéxitos en el borrador estándar C ++ 17 N4659 , la única referencia que puedo encontrar al overrideidentificador es:

5 Si una función virtual está marcada con la anulación virt-specifier y no anula una función miembro de una clase base, el programa está mal formado. [Ejemplo:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

- ejemplo final]

así que creo que posiblemente explotar programas incorrectos es en realidad el único efecto.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente