Função com o mesmo nome, mas assinatura diferente na classe derivada
-
03-07-2019 - |
Pergunta
Eu tenho uma função com o mesmo nome, mas com assinatura diferente em uma base e classes derivadas. Quando eu estou tentando usar a função da classe base em outra classe que herda da derivada, eu 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){};
de B
classe, ou se eu mudar o nome de foo1
, tudo funciona bem.
Qual é o problema com isso?
Solução
Funções em classes derivadas que não substituem funções na classe base, mas que tem o mesmo nome hide outras funções com o mesmo nome na classe base.
É geralmente considerado uma má prática ter ter funções em classes derivadas, que têm o mesmo nome de funções na classe baixa que não se destinam a substituir as funções de classe de base como o que você está vendo não é geralmente um comportamento desejável. Geralmente é preferível dar diferentes funções diferentes nomes.
Se você precisa chamar a função de base você precisará âmbito da chamada usando A::foo(s)
. Note-se que isso também iria desativar qualquer mecanismo de função virtual para A::foo(string)
ao mesmo tempo.
Outras dicas
É porque pesquisa de nome pára se encontrar um nome em uma das suas bases. Ele não vai olhar para além de outras bases. A função no B sombras a função em A. Você tem que re-declarar a função de A no âmbito do B, de modo que ambas as funções são visíveis de dentro 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);
}
};
Edit: A descrição real do padrão dá é (de 10,2 / 2):
As seguintes etapas definir o resultado da pesquisa de nome em um escopo de classe, C. Primeiro, cada declaração para o nome na classe e em cada um dos seus sub-objectos de classe base é considerado. Um nome membro f em um sub objecto B esconde um nome de f membro em um sub-objeto A se A é uma classe de sub-base objeto de B. Qualquer declaração que são tão ocultas são eliminados da consideração. Cada uma dessas declarações que foi introduzido por um utilizando-declaração é considerado a partir de cada sub-objeto de C, que é do tipo que contém o decla- ção designado pelo usando-declaration.96) Se o conjunto resultante de declarações não são todas da sub-objectos do mesmo tipo, ou o conjunto tem um membro não-estático e inclui membros de sub-objectos distintos, existe uma ambigüidade eo programa está mal-formado. Caso contrário, esse conjunto é o resultado da pesquisa.
Tem o seguinte a dizer em outro lugar (logo acima dele):
Para uma expressão id [ algo como "foo" ], pesquisa de nome começa no âmbito classe deste; para um-id qualificada [ algo como "A :: foo", A é um nome de nested-especificador ], pesquisa de nome começa no âmbito do nested-name-especificador. pesquisa de nome ocorre antes de controle de acesso (3.4, cláusula 11).
([...] colocar por mim). Note-se que significa que mesmo se o seu foo em B é privado, o foo em A ainda não serão encontrados (porque o controle de acesso acontece mais tarde).