2010-06-02 8 views
24
#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 se compila. Sin embargo, cuando declaro la función virtual en la subclase, compila bien.Por qué tengo que redeclarar una función virtual al anular [C++]

Si el compilador ya tiene la firma de la función que sobrescribirá la subclase, ¿por qué es necesaria una redeclaración?

¿Algún conocimiento?

+2

¿Qué error de compilador obtiene? –

+0

Aunque en este ejemplo vemos una clase base abstracta, la pregunta también es válida en general. – xtofl

+0

Podría, aunque sin saber qué compilador está utilizando, podría no obtener el mismo error (o ninguno) :) –

Respuesta

21

El redeclaración es necesaria porque:

  • La norma dice.
  • Facilita el trabajo del compilador al no subir la jerarquía para comprobar si existe tal función.
  • 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.
+0

¡Gracias! Eso tiene sentido. –

+0

@Matt Ellen: No hay problema –

+1

The = 0; al final de la declaración significa que TIENE que definirlo en la clase derivada. No es que quieras hacerlo. –

2

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 implementarlo. No hacerlo es un error de compilación.

+0

Pero seguramente el compilador sabe esperarlo en la implementación. ¿Para qué sirve la declaración del extracto? –

+0

@Matt Ellen: Vea mi respuesta –

+0

@Matt El estándar de lenguaje dice que es obligatorio, esto no tiene nada que ver con las clases abstractas, todas las funciones virtuales (y de hecho todas las funciones) funcionan de esa manera. –

2

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

+0

Ahora ese es un buen argumento para poder _no_ declarar 'quack'. Pero ¿cuál es el argumento para _having_ declararlo? – xtofl

1

Hasta que proporcione una implementación, todas las clases que heredan de una clase que contiene PVF son abstractas; no se pueden crear instancias. Para proporcionar una implementación de este tipo, debe declarar la función en la clase.

1

Declarar los métodos en cada clase le indicará 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 deberá saber el compilador la firma de quack()?

BigDuck aDuck; 
aDuck.quack(); 
5

Porque C++ separa 'declaration' de 'polymorphism': 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 la 'clase abstracta': no ​​se puede crear una instancia de BigDuck porque no tiene implementación de cuack en su interfaz.

Generalizando el problema, se puede declarar la función de base no virtual pura:

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

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

En este caso, el compilador se quejará de que tiene un símbolo BigDuck::quack que no fue declarada. Esto no tiene nada que ver con las clases abstractas ni nada.

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

12

Si cambia:

virtual void quack() = 0; 

a

virtual void quack(); 

Compilará sin implementar charlatán() en HugeDuck.

the = 0; al final de la declaración de la función, básicamente dice que todos los BigDucks cuajarán, pero que cada pato derivado debe implementarlo. Al eliminar el = 0; se llamará al curandero BigDuck a menos que implementes el curandero en HugeDuck.

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

Como nota al margen, dado que todos los patos pueden piratear tal vez su clase original de pato que no podemos ver debería implementar quack() en su lugar?

+0

¿HugeDuck == BigDuck'? ¿Es esta una segunda clase derivada que estás proponiendo, o un error tipográfico? (¿o una clase derivada de 'BigDuck', u otra cosa)? –

Cuestiones relacionadas