Por qué tengo que volver a declarar una función virtual mientras sobrescribo [C++]


#include <iostream>
using namespace std;

class Duck {
public:
        virtual void quack() = 0;
};

class BigDuck : public Duck {
public:
  //  void quack();   (uncommenting will make it compile)

};

void BigDuck::quack(){ cout << "BigDuckDuck::Quack\n"; }

int main() {
        BigDuck b;
        Duck *d = &b;
        d->quack();

}

El código anterior no compila. Sin embargo, cuando declaro la función virtual en la subclase, entonces se compila bien.

Si el compilador ya tiene la firma de la función que la subclase anulará, entonces ¿por qué se requiere una redeclaración?

¿Alguna idea?

Author: liang, 2010-06-02

7 answers

La redeclaración es necesaria porque:

  • La norma lo dice.
  • Facilita el trabajo del compilador al no escalar la jerarquía para verificar si dicha función existe.
  • Es posible que desee declararlo más bajo en la jerarquía.
  • Para instanciar la clase el compilador debe saber que este objeto es concreto.
 21
Author: the_drow,
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
2010-06-02 13:22:59

Si cambia:

virtual void quack() = 0;

A

virtual void quack();

Compilará sin implementar quack() en HugeDuck.

El = 0; al final de la declaración de la función está esencialmente diciendo que todos los BigDucks cuack, pero que tiene que ser implementado por cada pato derivado. Quitando el = 0; el quack BigDuck será llamado a menos que implemente quack en HugeDuck.

EDIT: Para aclarar el = 0; está diciendo que la clase derivada tendrá la definición para la función. En tu ejemplo está esperando que HugeDuck defina quack (), pero como lo has comentado no lo hace.

Como nota al margen, ya que todos los patos pueden cuac quizás tu clase original de Patos que no podemos ver debería implementar quack() en su lugar?

 12
Author: Ben Burnett,
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
2010-06-02 13:39:36

Porque C++ separa 'declaración' de 'polimorfismo': cualquier función necesita una declaración para el compilador, independientemente de si es virtual o no.

Su ejemplo no va lo suficientemente lejos, tiene el problema de 'clase abstracta': un BigDuck no puede ser instanciado porque no tiene implementación de quack en su interfaz.

Generalizando el problema, podemos declarar la función base no pura virtual:

class Duck { public: virtual void quack(){} };

class BigDuck : public Duck {}; 
void BigDuck::quack(){ cout << "QUACK!"; }//overrides, but doesn't declare

Aquí, el compilador se quejará de que tiene un símbolo BigDuck::quack que no fue declarado. Esto no tiene nada que ver con clases abstractas ni nada.

(Nota: el ccg dice: error: no 'void BigDuck::q()' member function declared in class 'BigDuck' )

 5
Author: xtofl,
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
2010-06-02 13:34:03

La definición de Quack() en su clase base es "abstracta" - no tiene implementación. Esto le dice al compilador que su clase derivada debe implementarla. No hacerlo es un error de compilación.

 2
Author: GalacticCowboy,
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
2010-06-02 13:18:42

BigDuck podría ser otra clase abstracta y es posible que no desee implementar quack hasta que llegue a la clase base ReallyBigDuck.

 2
Author: Pace,
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
2010-06-02 13:19:03

Declarar los métodos en cada clase le dirá al compilador que la clase proporciona la implementación diferente para el método.

También, en caso de que desee crear los objetos de BigDuck en la pila, entonces cómo compilador will debe saber la firma de quack().

BigDuck aDuck;
aDuck.quack();
 1
Author: aJ.,
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
2010-06-02 13:21:23

Hasta que proporcione una implementación, todas las clases que heredan de una clase que contiene Pure Virtual Function son abstractas - no se pueden crear instancias. Para proporcionar tal implementación, debe declarar la función en la clase.

 1
Author: Rndp13,
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
2018-04-14 19:13:57