Johannes 'Antwort deckt die grundlegenden Fakten ab. Aber da ist noch ein bisschen mehr. So betrachten
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.
}
Wenn ich kompilieren ich, wie jetzt durch (nach Johannes' Antwort) Sie erwarten,
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> _
Wie hängt davon ab, zu klären, ob es in Ordnung ist mit einem einzigen Unter -Objekt der Klasse Base
(wie es der Fall ist, wenn Base
eine reine Schnittstelle ist) oder Intermediate
erfordert wirklich ein eigenes Base
Unterobjekt.
Der letzte Fall, zwei Base
Unterobjekte, ist wahrscheinlich nicht das, was Sie wollen, aber wenn Sie das dann dann eine Heilung ist, um noch eine andere Zwischenklasse einzuführen, sagen wir ResolvableBase
.
Like:
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.
}
Im ersten Fall, in dem z.B.Base
ist eine Schnittstelle und nur ein Base
Unterobjekt ist erforderlich, können Sie virtuelle Vererbung verwenden.
Die virtuelle Vererbung fügt in der Regel etwas Laufzeit-Overhead hinzu, und Visual C++ ist nicht allzu gern davon.
Aber es lässt Sie eine Implementierung einer Schnittstelle "in erben", wie in Java und 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.
}
Subtlety: Ich habe die Vererbungsliste bestellen, um g ++ sillywarnings über Initialisierungsreihenfolge zu vermeiden geändert.
Belästigung: Visual C++ gibt C4250 alberywarning über Vererbung (der Implementierung) über Dominanz aus. Es ist wie "Warnung: Sie verwenden eine Standard-Hauptfunktion". Naja, schalte es einfach aus.
Beifall & hth.,
Es ist kein Compiler-Fehler seine [nur eine Warnung] (http://ideone.com/Pe0nK). –
Ich würde mir vorstellen, dass der Aufruf von Derived-> YourMethod (5) in Ordnung sein sollte ... schließlich ist YuorMethod sowohl in Base als auch in Intermediate virtuell, also warum kannst du deine eigene Implementation nicht definieren. Sie rufen die Basisfunktionen nicht auf irgendeine Weise an, also sollte das öffentliche private TIHNG nicht wichtig sein? – thecoshman
@ Prasoon: Bearbeitet. – nakiya