2010-01-24 12 views
19

Problem:C++ virtual spadkowe

class Base { 
public: 
    Base(Base* pParent); 
    /* implements basic stuff */ 
}; 

class A : virtual public Base { 
public: 
    A(A* pParent) : Base(pParent) {} 
    /* ... */ 
}; 

class B : virtual public Base { 
public: 
    B(B* pParent) : Base(pParent) {} 
    /* ... */ 
}; 

class C : public A, public B { 
public: 
    C(C* pParent) : A(pParent), B(pParent) {} // - Compilation error here 
    /* ... */ 
}; 

W pozycji danej gcc narzeka, że ​​nie może się równać funkcji połączenia do bazy(), czyli konstruktora domyślnego. Ale C nie dziedziczy bezpośrednio od Bazy, tylko przez A i B. Dlaczego więc Gcc narzeka tutaj?

Pomysły? TIA /Rob

+0

Kompilacja odbywa się bez-RTTI zestawie, może być problem? – Robert

+6

Nie, dziedziczenie jest kompilacją, RTTI nie będzie wymagane. – GManNickG

Odpowiedz

43

virtual klasy podstawowe są specjalne, ponieważ są inicjalizowane przez najbardziej pochodną klasę, a nie przez żadne pośrednie klasy bazowe dziedziczące z wirtualnej bazy. Który z potencjalnych inicjatorów wielokrotnych byłby właściwym wyborem do zainicjowania jednej bazy?

Jeśli skonstruowana klasa najbardziej nie wyświetla jej na swojej liście inicjalizacji, to wirtualna klasa bazowa jest inicjowana za pomocą domyślnego konstruktora, który musi istnieć i być dostępny.

Należy pamiętać, że wirtualny identyfikator bazy może być używany na liście inicjalizacyjnej konstruktora, nawet jeśli nie jest bezpośrednią podstawą danej klasy.

+0

+1, Najbardziej precyzyjna odpowiedź :) –

+0

Dodatek: Zauważ, że klasa abstrakcyjna nigdy nie może zainicjować swojej wirtualnej bazy, więc nie musi wywoływać wirtualnych baz ctor w liście inicjującej ctors, nawet jeśli nie istnieje domyślny ctor. – Deduplicator

+0

Oznacza to, że inicjalizacja klasy macierzystej A i B (tj. ": Base (pParent)") jest ignorowana podczas konstruowania bardziej pochodnej klasy? – Chris

5

Po zadeklarowaniu niestandardowego konstruktora domyślny konstruktor jest wyłączony. W dziedziczeniu wirtualnym musisz wywołać bezpośrednio odziedziczony konstruktor, ponieważ w przeciwnym razie nie wiedziałby, czy zainicjować przez A, czy przez B.

7

Trzeba jawnie wywołać konstruktora do bazy z katalogu C:

class C : public A, public B { 
public: 
C(C* pParent) : Base(pParent), A(pParent), B(pParent) {} 
/*... */ 
}; 
+0

Nie wiedziałem, że możesz to zrobić. Czy to oznacza, że ​​kompilator ignoruje kod w '' 'i' B' '' '' '' '' '' '' '' '' '' '' '' '' '' – quamrana

+1

Nie tylko, że możesz to zrobić, musisz to zrobić. Żaden kod nie jest ignorowany. Konstruktor dla 'Base' zostanie wywołany tylko raz, a następnie korpus konstruktorów dla A i B, a następnie korpus konstruktora dla C. – BenG

+0

Rozumiem teraz kolejność wywołań konstruktora i przyczyny tego, z wyjątkiem I zwykle mają klasę podstawową z tylko domyślnym konstruktorem, więc nie muszę mieć jawnych wywołań do 'Base()'. Na pewno w przykładzie z PO kompilatory muszą nadal ignorować wskazówkę programistów, że 'Base (pParent)' powinno być wywoływane bezpośrednio z c "leka zarówno" A "jak i' B'? – quamrana

Powiązane problemy