Odpowiedź Johannesa obejmuje podstawowe fakty. Ale jest w tym trochę więcej. Tak więc, należy rozważyć
struct Base
{
Base(int) {}
void foo() const {}
};
struct Intermediate: Base
{
Intermediate(int x)
: Base(x)
{}
};
struct Derived: Intermediate, Base
{
Derived(int x)
: Intermediate(x)
, Base(x) // OK
{}
};
int main()
{
Derived o(667);
o.foo(); // !Oops, ambiguous.
o.Base::foo(); // !Oops, still ambiguous.
}
Kiedy kompilacji otrzymuję, jak teraz (po Johannes' odpowiedź) będziesz oczekiwać,
C:\test> gnuc x.cpp
x.cpp:15: warning: direct base 'Base' inaccessible in 'Derived' due to ambiguity
x.cpp: In function 'int main()':
x.cpp:25: error: request for member 'foo' is ambiguous
x.cpp:4: error: candidates are: void Base::foo() const
x.cpp:4: error: void Base::foo() const
x.cpp:26: error: 'Base' is an ambiguous base of 'Derived'
C:\test> msvc x.cpp
x.cpp
x.cpp(15) : warning C4584: 'Derived' : base-class 'Base' is already a base-class of 'Intermediate'
x.cpp(2) : see declaration of 'Base'
x.cpp(7) : see declaration of 'Intermediate'
x.cpp(25) : error C2385: ambiguous access of 'foo'
could be the 'foo' in base 'Base'
or could be the 'foo' in base 'Base'
x.cpp(25) : error C3861: 'foo': identifier not found
C:\test> _
Jak rozwiązać zależy od tego, czy to jest w porządku z jednym sub -obiekt klasy Base
(tak jak w przypadku, gdy Base
jest czystym interfejsem), lub Intermediate
naprawdę wymaga własnego sub-obiektu Base
.
tym drugim przypadku dwa Base
podrzędne obiekty, prawdopodobnie nie jest to, co chcesz, ale jeśli chcesz, aby następnie następnie jedno lekarstwo jest przedstawić kolejną klasę pośrednią, powiedzmy, ResolvableBase
.
jak:
struct Base
{
Base(int) {}
void foo() const {}
};
struct Intermediate: Base
{
Intermediate(int x)
: Base(x)
{}
};
struct ResolvableBase: Base
{
ResolvableBase(int x): Base(x) {}
};
struct Derived: Intermediate, ResolvableBase
{
Derived(int x)
: Intermediate(x)
, ResolvableBase(x)
{}
};
int main()
{
Derived o(667);
o.ResolvableBase::foo(); // OK.
}
W pierwszym przypadku, gdy npBase
jest interfejsem i wymagany jest tylko jeden sub-obiekt Base
, można używać dziedziczenia wirtualnego.
Dziedziczenie wirtualne zazwyczaj zwiększa obciążenie środowiska wykonawczego, a program Visual C++ go nie lubi.
Ale to pozwala „dziedziczą w” implementacji interfejsu, jak Java i C#:
struct Base
{
Base(int) {}
virtual void foo() const = 0;
};
struct Intermediate: virtual Base
{
Intermediate(int x)
: Base(x)
{}
void foo() const {} // An implementation of Base::foo
};
struct Derived: virtual Base, Intermediate
{
Derived(int x)
: Base(x)
, Intermediate(x)
{}
};
int main()
{
Derived o(667);
o.foo(); // OK.
}
Subtelność: Zmieniłem dziedziczenia listy zamówienia w celu uniknięcia g ++ sillywarnings o kolejności inicjalizacji.
Podrażnienie: problemy z Visual C++ C4250 dotyczące dziedziczenia (implementacji) poprzez dominację. To jest jak "ostrzeżenie: używasz standardowej funkcji głównej". No cóż, po prostu wyłącz to.
Cheers & HTH.,
To nie błąd kompilatora jego [tylko ostrzeżenie] (http://ideone.com/Pe0nK). –
Wyobrażam sobie, że wywoływanie Derived-> YourMethod (5) powinno być w porządku ... w końcu, zarówno w Bazie, jak i Intermediate, YuorMethod jest wirtualny, więc dlaczego nie możesz zdefiniować własnej implozji. Nie odwołujesz się do funkcji bazowych w żaden sposób, więc publiczny prywatny tihng nie powinien mieć znaczenia? – thecoshman
@Prasoon: Edytowano. – nakiya