Funzione con lo stesso nome ma firma diversa nella class derivata

Ho una funzione con lo stesso nome, ma con firma diversa in una base e classi derivate. Quando sto cercando di utilizzare la funzione della class base in un’altra class che eredita dal derivato, ricevo un errore. Vedere il seguente codice:

class A { public: void foo(string s){}; }; class B : public A { public: int foo(int i){}; }; class C : public B { public: void bar() { string s; foo(s); } }; 

Ricevo il seguente errore dal compilatore gcc:

 In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int) 

Se rimuovo int foo(int i){}; dalla class B , o se lo rinominano da foo1 , tutto funziona bene.

Qual è il problema con questo?

Le funzioni nelle classi derivate che non eseguono l’override delle funzioni nelle classi base ma che hanno lo stesso nome nascondono altre funzioni con lo stesso nome nella class base.

Generalmente è considerata una ctriggers pratica avere funzioni in classi derivate che hanno lo stesso nome di funzioni nella class di basso che non intendono sovrascrivere le funzioni della class base, poiché ciò che si sta vedendo non è un comportamento solitamente desiderabile. Di solito è preferibile dare nomi diversi a funzioni diverse.

Se è necessario chiamare la funzione di base, sarà necessario circoscrivere la chiamata utilizzando A::foo(s) . Notare che ciò disabilita anche qualsiasi meccanismo di funzione virtuale per A::foo(string) allo stesso tempo.

È perché la ricerca dei nomi si interrompe se trova un nome in una delle tue basi. Non guarderà oltre in altre basi. La funzione in B ombreggia la funzione in A. Devi dichiarare nuovamente la funzione di A nell’ambito di B, in modo che entrambe le funzioni siano visibili all’interno di B e C:

 class A { public: void foo(string s){}; }; class B : public A { public: int foo(int i){}; using A::foo; }; class C : public B { public: void bar() { string s; foo(s); } }; 

Modifica: la descrizione reale fornita dallo standard è (dal 10.2 / 2):

Le seguenti fasi definiscono il risultato della ricerca del nome in un ambito di class, C. In primo luogo, viene considerata ogni dichiarazione per il nome nella class e in ciascuno degli oggetti secondari della class base. Un nome membro f in un sotto-object B nasconde un nome membro f in un sotto-object A se A è un sotto-object di class base di B. Qualsiasi dichiarazione che è così nascosta viene eliminata dalla considerazione. Ciascuna di queste dichiarazioni che è stata introdotta da una dichiarazione d’uso è considerata da ciascun sottoobject di C che è del tipo che contiene la dichiarazione designata dalla dichiarazione d’uso.96) Se l’insieme risultante di dichiarazioni non è tutto da oggetti secondari dello stesso tipo, oppure l’insieme ha un membro non statico e include membri di sotto-oggetti distinti, c’è un’ambiguità e il programma è mal formato. Altrimenti quell’insieme è il risultato della ricerca.

Ha il seguente da dire in un altro posto (appena sopra di esso):

Per un’espressione id [ qualcosa come “pippo” ], la ricerca dei nomi inizia nell’ambito della class di questo; per un id qualificato [ qualcosa come “A :: foo”, A è uno specificatore nome-nidificato ], la ricerca del nome inizia nell’ambito dello specificatore nome-nidificato. La ricerca dei nomi avviene prima del controllo degli accessi (3.4, clausola 11).

([…] messo da me). Nota che significa che anche se il tuo foo in B è privato, il foo in A non sarà ancora trovato (perché il controllo dell’accesso avviene più tardi).