2010-06-02 9 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(); 

} 

Powyższy kod nie kompiluje. Jednakże, gdy deklaruję wirtualną funkcję w podklasie, kompiluje się ona poprawnie.Dlaczego muszę redeclare funkcji wirtualnej podczas przesłonięcia [C++]

Jeśli kompilator ma już podpis funkcji, której podklasa zastąpi, dlaczego jest wymagana redeclaracja?

Jakieś spostrzeżenia?

+2

Jakiego błędu kompilatora otrzymujesz? –

+0

Mimo że w tym przykładzie widzimy abstrakcyjną klasę podstawową, to pytanie jest również ogólnie poprawne. – xtofl

+0

Mogłem, chociaż nie wiedząc, jakiego kompilatora używasz, może nie dostać tego samego (lub jakiegokolwiek) błędu :) –

Odpowiedz

21

konieczna jest ponowna ponieważ:

  • Standardowa tak mówi.
  • Ułatwia to pracę kompilatora, nie wspinając się po hierarchii, aby sprawdzić, czy taka funkcja istnieje.
  • Możesz chcieć zadeklarować go niżej w hierarchii.
  • Aby utworzyć instancję klasy, kompilator musi wiedzieć, że ten obiekt jest konkretny.
+0

Dzięki! To ma sens. –

+0

@Matt Ellen: Nie ma problemu –

+1

The = 0; na końcu deklaracji oznacza, że ​​MUSISZ zdefiniować ją w klasie pochodnej. Nie, żebyś chciał. –

2

Definicja Quack() w twojej klasie bazowej jest "abstrakcyjna" - nie ma implementacji. To powie kompilatorowi, że twoja pochodząca klasa musi ją zaimplementować. W przeciwnym razie wystąpił błąd kompilacji.

+0

Ale na pewno kompilator wie, że oczekuje tego w implementacji. Do czego służy deklaracja wypakowania? –

+0

@Matt Ellen: Zobacz moją odpowiedź –

+0

@Matt Standard językowy mówi, że jest to wymagane - nie ma to nic wspólnego z klasami abstrakcyjnymi, wszystkie funkcje wirtualne (a nawet wszystkie funkcje) działają w ten sposób. –

2

BigDuck może być kolejną klasą abstrakcyjną i możesz nie chcieć zaimplementować znachora, aż dotrzesz do klasy bazowej ReallyBigDuck.

+0

To jest dobry argument za to, że _nie_ deklarujemy 'szarlatana'. Ale jaki jest argument za tym, by _wstać_, aby to zadeklarować? – xtofl

1

Do czasu przedstawienia implementacji wszystkie klasy dziedziczące z klasy zawierającej PVF są abstrakcyjne - nie można ich utworzyć. Aby zapewnić taką implementację, musisz zadeklarować funkcję w klasie.

1

Zgłaszanie metod w poszczególnych klasach powie kompilatorowi, że klasa zapewnia różne implementacje metody.

Również, jeśli chcesz utworzyć obiekty BigDuck na stosie, to w jaki sposób kompilator powinien znać podpis quack().

BigDuck aDuck; 
aDuck.quack(); 
5

Ponieważ C++ oddziela "deklarację" od "polimorfizmu": jakakolwiek funkcja wymaga deklaracji dla kompilatora, niezależnie od tego, czy jest to wirtualne czy nie.

Twój przykład nie idzie wystarczająco daleko, ma on problem z "klasą abstrakcyjną": nie można utworzyć instancji BigDuck, ponieważ nie ma on implementacji szarego interfejsu.

Uogólniając problem, możemy zadeklarować funkcję bazową nie czysta wirtualna:

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

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

tu, kompilator będzie narzekać, że ma symbol BigDuck::quack który nie został uznany. Nie ma to nic wspólnego z klasami abstrakcyjnymi lub czymkolwiek.

(Uwaga: gcc mówi: error: no 'void BigDuck::q()' member function declared in class 'BigDuck' )

12

przypadku zmiany:

virtual void quack() = 0; 

do

virtual void quack(); 

będzie skompilować bez wdrożenia szarlatanowi() w HugeDuck.

the = 0; na końcu deklaracji funkcji zasadniczo mówi się, że wszystkie gracze BigDucks będą znachorować, ale muszą zostać zaimplementowane przez każdą wyprowadzoną kaczkę. Usuwając = 0; kwak BigDuck zostanie wywołany, chyba że zaimplementujesz szarlatana w HugeDuck.

EDYCJA: Aby wyjaśnić = 0; mówi, że klasa pochodna będzie miała definicję funkcji. W twoim przykładzie spodziewasz się, że HugeDuck zdefiniuje funkcję quack(), ale jak już ją skomentował, nie robi tego.

Na marginesie, skoro wszystkie kaczki potrafią znudzić, być może, twoja oryginalna klasa Duck, której nie widzimy, powinna zaimplementować funkcję quack()?

+0

Czy 'HugeDuck == BigDuck'? Czy to jest druga klasa pochodna, którą proponujesz, czy literówka? (lub klasa pochodna 'BigDuck' lub coś innego)? –

Powiązane problemy