2011-08-26 3 views
6

Sono confuso sul motivo per cui il compilatore C++ non accetterà questo:Perché il compilatore C++ non disambigura tra un pubblico ereditato e un metodo privato ereditato con lo stesso nome?

class Foo { 
    private: void Baz() { } 
    }; 

    class Bar { 
    public: void Baz() { 
    }; 

    class FooBar : public Foo, public Bar { }; 

    void main() { 
    FooBar fb; 
    fb.Baz(); 
    } 

Il gcc errore dà è:

request for member ‘Baz’ is ambiguous 
candidates are: void Bar::Baz() 
       void Foo::Baz() 

ma non è ovvio che voglio Bar :: Baz(), dal momento che Foo :: Baz() è privato? Perché il compilatore non disambigui qui?

risposta

7

La risoluzione dei nomi funziona in due fasi. Prima viene cercato il nome e il nome viene controllato per l'accesso. Se il nome visualizzato è ambiguo, l'accesso non viene mai considerato.

Per quanto riguarda il motivo, forse è un design di linguaggio deliberato, ma penso che sia più probabile che sia solo per semplificare il processo di risoluzione dei nomi. Le regole sono già diabolicamente complicate.

+0

È un deliberato. Non semplifica il compilatore, al contrario, è leggermente più complicato perché l'accesso deve essere controllato come un ulteriore passaggio. – curiousguy

3

Non è ovvio: potresti aver desiderato chiamare il membro privato (se possibile).

Formalmente, le regole della lingua dicono che il nome viene risolto per primo e viene selezionato il sovraccarico migliore. Solo dopo c'è un controllo per l'accessibilità.

1

Le restrizioni di accesso non influiscono sull'eredità. Tu erediti sempre tutto da tutte le classi base. Nel tuo caso che può sembrare inutile, ma prendere in considerazione una versione leggermente modificata in cui la funzione privata è virtuale:

class Base 
{ 
    virtual void secret_power() { /* innocent default */ } 
public: 
    void use_me() { secret_power(); } 
}; 

class Derived : public Base 
{ 
    virtual void secret_power() { /* overriding implementation here */ } 
}; 

Ora per qualsiasi Base& si può sempre chiamare l'interfaccia pubblica non virtuale use_me(), ma le vostre classi derivate forniscono il implementazione tramite un virtual privato.

2

Per consentire ciò, è necessario considerare se ci si trova o meno in un contesto che consente di chiamare un metodo privato o meno. Se ciò fosse consentito, la chiamata:

fb.Baz() 

potrebbe avere funzionalità completamente diverse a seconda che lo stiate chiamando da un contesto pubblico o privato. E questo non è proprio in linea con il modo in cui la lingua funziona.

+1

Questo è un punto eccellente. Grazie! –

1

Come altri hanno già detto, prima viene cercato il nome, quindi vengono applicate le restrizioni di accesso. Puoi aggirare il problema chiamando esplicitamente il metodo che desideri, come in

fb.Bar::Baz() 
+0

Ma attenzione come la sintassi qualificata fa due cose: 1) controllo nome ricerca 2) disabilitare la spedizione dinamica (non in questo caso particolare, ma potrebbe). – curiousguy