7
class messageA { 
}; 

class messageB { 
}; 

template<class T> 
class queue { 
public: 
    virtual ~queue() {} 
    void submit(T& x) {} 
}; 

class A : public queue<messageA>, public queue<messageB> 
{ 
}; 

int main() 
{ 
    A aa; 
    aa.submit(messageA()); 
    aa.submit(messageB()); 
} 

Il mio primo pensiero è, il codice di cui sopra dovrebbe andare bene, in quanto la classe A conterrà 2 funzioni di invio sovraccarico, che accetterà l'oggetto messageA e messageB.Modello di ereditarietà multipla Classe

Tuttavia, il compilatore mi dà il seguente errore:

Posso sapere il motivo per cui v'è un ambiguo? Non è abbastanza ovvio che, per la prima chiamata di invio, voglio chiamare la versione messageA? Per la seconda chiamata di invio, voglio chiamare la versione messageB?


------ Build started: Project: main, Configuration: Release Win32 ------ 
Compiling... 
main.cpp 
.\main.cpp(21) : error C2385: ambiguous access of 'submit' 
     could be the 'submit' in base 'queue<messageA>' 
     or could be the 'submit' in base 'queue<messageB>' 
.\main.cpp(21) : error C3861: 'submit': identifier not found 
.\main.cpp(22) : error C2385: ambiguous access of 'submit' 
     could be the 'submit' in base 'queue<messageA>' 
     or could be the 'submit' in base 'queue<messageB>' 
.\main.cpp(22) : error C2664: 'queue<T>::submit' : cannot convert parameter 1 from 'messageB' to 'messageA &' 
     with 
     [ 
      T=messageA 
     ] 
.\main.cpp(22) : error C3861: 'submit': identifier not found 
+0

Si noti che la conversione implicita da 'messageA' a' messageA &' non è standard C++; un riferimento non const può essere associato a un lvalue (http://msdn.microsoft.com/en-us/library/186yxbac(VS.80).aspx). La funzione 'submit()' dovrebbe accettare 'const T &' piuttosto che 'T &'. –

risposta

11

non ho compilatore in questo momento, ma credo che un'eredità poteva nascondere l'altro: Il compilatore utilizzerà Koenig Lookup per trovare il simbolo a destra, e se non ricordo male, una volta che il compilatore trovare un adeguato simbolo (cioè un metodo chiamato "invio"), smetterà di cercare gli altri in ambito genitore e/o esterno.

In questo caso, ho pensato che entrambe le classi ereditarie sarebbero state cercate per il simbolo, ma senza il tuo compilatore esatto (Visual C++ 2003? 2008? 2010?), Non posso indovinare molto di più.

Dopo alcune riflessioni, un'altra possibilità è che il compilatore ha trovato entrambi i simboli, ma non è in grado di decidere quale chiamare (in quel momento della risoluzione simbolo, il compilatore si preoccupa solo per il nome simbolo, non il suo prototipo esatto). Credo che questa ultima spiegazione sia quella giusta.

Prova ad aggiungere utilizzando le istruzioni nelle classi derivate:

class A : public queue<messageA>, public queue<messageB> 
{ 
    using queue<messageA>::submit ; 
    using queue<messageB>::submit ; 
} ; 

di portare sia il presentare i metodi direttamente nel campo di applicazione di una classe.

Nota anche che i metodi di invio stanno prendendo i messaggi come riferimento non const, mentre nel costruttore i parametri del messaggio sono temporanei (e quindi valori const-r).

Re-scrittura del principale:

int main() 
{ 
    A aa; 
    messageA mA ; 
    messageA mB ; 
    aa.submit(mA); 
    aa.submit(mB); 
} 

potrebbe aiutare a compilare (questo potrebbe spiegare l'errore del compilatore sulla linea 22).

Oppure è possibile modificare il prototipo dei metodi di invio per accettare riferimenti const anziché riferimenti non const.

Nota: Sempre senza compilatore, in modo da cercare di brain-debug del codice ... :-P ...

+0

"_ Immagino che un'eredità possa nascondere l'altra_" No. "_Il compilatore userà Koenig Lookup_" No, non lo farà. "Il compilatore ha trovato entrambi i simboli, ma non è in grado di decidere quale chiamare" Sì. – curiousguy

+0

"_temporaries (e quindi, const r-values) ._" No, i temporanei sono ** non ** costanti. – curiousguy

1
Something* smth1 = ((Base<Something> *)d)->createBase<Something>(); 

Il codice sopra funziona bene.

+0

"' ((Base *) d) '" Brutto e molto pericoloso: si nasconde un problema di tipo serio con questo cast in stile C. OTOH, questo 'Base & dBase = * d; dBase.createBase (); 'è sicuro. – curiousguy