La risposta di Johannes copre i fatti di base. Ma c'è un po 'di più. Così, in considerazione
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.
}
Quando compilo ricevo, come ormai (dopo Johannes' risposta) ti aspetta,
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> _
Come risolvere dipende dal fatto che è tutto a posto con un unico sub -oggetto della classe Base
(come nel caso in cui Base
è un'interfaccia pura) o Intermediate
richiede realmente il proprio oggetto secondario Base
.
L'ultimo caso, due sottooggetti Base
, non è probabilmente quello che si desidera, ma se si desidera che quindi una cura è di introdurre ancora un'altra classe intermedia, ad esempio, ResolvableBase
.
piace:
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.
}
Nel primo caso, in cui ad esempioBase
è un'interfaccia e è necessario un solo oggetto secondario Base
, è possibile utilizzare l'ereditarietà virtuale.
L'ereditarietà virtuale in genere aggiunge un sovraccarico di runtime e Visual C++ non è troppo appassionato di esso.
Ma consente di "ereditano in" un'implementazione di un'interfaccia, come in Java e 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: ho cambiato l'ordine di lista di successione al fine di evitare g ++ sillywarnings su ordine di inizializzazione.
Annoyance: Visual C++ emette un C450 sillywarning sull'ereditarietà (dell'implementazione) tramite il dominio. È come "avviso: stai usando una funzione principale standard". Oh bene, spegnilo.
Acclamazioni & hth.,
suo non è un errore del compilatore suo [solo un avvertimento] (http://ideone.com/Pe0nK). –
Immagino che chiamare Derived-> YourMethod (5) dovrebbe andare bene ... dopotutto, sia in Base che in Intermediate, YuorMethod è virtuale, quindi perché non puoi definire la tua implosione. Non stai chiamando le funzioni di base in alcun modo, quindi il tihng privato pubblico non dovrebbe avere importanza? – thecoshman
@Prasoon: modificato. – nakiya