2011-07-17 20 views
16

Mam problem z dziedziczeniem C++.C++ Funkcja wirtualna jest ukryta

Mam hierarchię klas:

class A { 
public: 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

class B : public A { 
public: 
    virtual void onFoo(int i) {} 
}; 

class C : public B { 
}; 


int main() { 
    C* c = new C(); 
    c->onFoo(); //Compile error - doesn't exist 
} 

Moje pytanie brzmi: dlaczego nie to skompilować? Rozumiem, że C powinno dziedziczyć obie funkcje OnFoo od A - i faktycznie to się kompiluje, jeśli usuniesz redefinicję onFoo w B - ale g ++ daje błąd, że C nie ma funkcji onFoo().

Odpowiedz

33

problem, który doświadczasz jest związane, jak działa wyszukiwanie nazw w C++. W szczególności podczas rozwiązywania elementu kompilator będzie sprawdzał typ statyczny obiektu, do którego członek jest uzyskiwany. Jeśli identyfikator zostanie znaleziony w tej klasie, to wyszukiwanie zakończy się i (w przypadku funkcji składowych) rozpocznie się obliczanie przeciążenia. Jeśli identyfikator nie zostanie znaleziony, będzie on indeksował hierarchię, klasy po klasie, próbując zlokalizować identyfikator o wartości na jednym poziomie w czasie.

W konkretnym przypadku masz c->onFoo(); i c dla typu C. Kompilator nie widzi żadnej deklaracji onFoo w C, więc kontynuuje w górę w hierarchii. Kiedy kompilator sprawdza B, widzi, że na tym poziomie znajduje się deklaracja void onFoo(int i), więc przestaje wyszukiwać i próbuje rozwiązać problem przeciążenia. W tej chwili nie można rozwiązać problemu z przeciążeniem ze względu na niespójność argumentów.

Fakt, że deklaracja void onFoo(int) występuje w B poziomie skutkuje ukrywanie resztę przeciążenia w dowolnej klasy podstawy, jak zatrzyma odnośnika. Zauważ, że jest to problem z niewykwalifikowanym wyszukiwaniem, funkcja jest nadal dostępna i ma zastosowanie do obiektu, ale nie zostanie znaleziona przez regularne wyszukiwanie (nadal możesz ją nazwać c->A::onFoo()).

W jaki sposób radzić sobie z ukrywanie, najprostszym sposobem jest zatrudnienie deklarację korzystając przynieść funkcje w zakresie:

class B : A { 
public: 
    using A::onFoo; // All A::onFoo overloads are *considered* here 
    void onFoo(int); 
}; 

Efekt deklaracji using tutaj jest to, że gdy klasa B zostaje wyszukany, w poszukiwaniu identyfikatora onFoo, kompilator jest instruowany, aby uwzględnić wszystkie przeciążenia klasy onFoo w klasie bazowej, umożliwiając regularne wyszukiwanie w celu znalezienia A::onFoo().

+0

+1 - Ładne wyjaśnienie. – Mahesh

7

To jest ukrywanie nazwy, w zasadzie tylko B, a pozostałe przeciążenia w A są ukryte.

2

Metody klasy A i B powinny być publiczne. To i brakuje ci średników na końcu każdej deklaracji klasowej.

class A { 
public: 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

class B : public A { 
public: 
    virtual void onFoo(int i) {} 
}; 

class C : public B { 
}; 


int main() { 
    C* c = new C(); 
    c->onFoo(); //Compile error - doesn't exist 
} 
+0

To są poprawne punkty, ale twoja "poprawka" również się nie kompiluje. –

1

Zapomniałaś public: modyfikator przed metod klasy A i B. Tak więc, metody onFoo jest prywatny, a zatem nie jest widoczna wszędzie poza tymi klasami.

+0

Ups - to nie był problem, tylko ja przepisałem problem. Edytowane w celu naprawy –

12

Jeśli chcesz członkowie klasy bazowej do przeciążenia pochodzące członków klasy, którego chcesz użyć using:

struct A 
{ 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

struct B : A 
{ 
    using A::onFoo; 
    virtual void onFoo(int i) {} 
}; 

struct C : B 
{ 
}; 


int main() 
{ 
    C* c = new C(); 
    c->onFoo(); 
} 
-2

Chyba masz nieodebrane dodając ten w class B:

struct B : A 
{ 
    using A::onFoo; 
    virtual void onFoo(int i) {} 
    void onFoo() {} //This line missing in your code. 
}; 

Teraz to kompiluje!

Powiązane problemy