Função com o mesmo nome mas assinatura diferente na class derivada

Eu tenho uma function com o mesmo nome, mas com assinatura diferente em uma base e classs derivadas. Quando estou tentando usar a function da class base em outra class que herda da derivada, recebo um erro. Veja o seguinte código:

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); } }; 

Eu recebo o seguinte erro do compilador gcc:

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

Se eu remover int foo(int i){}; da class B , ou se eu mudar o nome de foo1 , tudo funciona bem.

Qual o problema com isso?

Funções em classs derivadas que não sobrescrevem funções em classs base, mas que possuem o mesmo nome, ocultarão outras funções de mesmo nome na class base.

Geralmente, é considerada prática ruim ter funções em classs derivadas que tenham o mesmo nome das funções na class de baixo que não pretendem replace as funções da class base, já que o que você está vendo não é geralmente um comportamento desejável. Geralmente, é preferível atribuir funções diferentes a nomes diferentes.

Se você precisar chamar a function base, você precisará escopo da chamada usando A::foo(s) . Note que isso também desativa qualquer mecanismo de function virtual para A::foo(string) ao mesmo tempo.

É porque a pesquisa de nomes pára se encontrar um nome em uma de suas bases. Não vai olhar além em outras bases. A function em B sombreia a function em A. Você tem que declarar novamente a function de A no escopo de B, para que ambas as funções sejam visíveis de dentro de 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); } }; 

Editar: A descrição real que o Padrão fornece é (de 10.2 / 2):

As etapas a seguir definem o resultado da pesquisa de nomes em um escopo de class, C. Primeiro, cada declaração para o nome na class e em cada um de seus subobjects de class base é considerada. Um nome de membro f em um sub-object B esconde um nome de membro f em um sub-object A se A é um subobject de class base de B. Quaisquer declarações que são tão ocultas são eliminadas da consideração. Cada uma dessas declarações que foi introduzida por uma declaração de uso é considerada como sendo de cada sub-object de C que é do tipo que contém a declaração designada pela declaração de utilização.96) Se o conjunto resultante de declarações não for todos de sub-objects do mesmo tipo, ou o conjunto tem um membro não estático e inclui membros de sub-objects distintos, há uma ambiguidade e o programa é mal formado. Caso contrário, esse conjunto é o resultado da pesquisa.

Tem o seguinte a dizer em outro lugar (logo acima):

Para uma expressão id [ algo como “foo” ], a pesquisa de nomes começa no escopo de class disso; para um ID qualificado [ algo como “A :: foo”, A é um nested-nome-especificador ], a pesquisa de nomes começa no escopo do nested-nome-especificador. A pesquisa de nomes ocorre antes do controle de access (3.4, cláusula 11).

([…] por mim). Note que isso significa que mesmo que seu foo em B seja privado, o foo em A ainda não será encontrado (porque o controle de access acontece mais tarde).