Escopo regras quando herdar - C ++
Pergunta
Eu estava lendo o C ++ 0x FAQ por Stroustrup e ficou preso com este código. Considere o seguinte código
struct A
{
void f(double)
{
std::cout << "in double" << std::endl;
}
};
struct B : A
{
void f(int)
{
std::cout << "in int" << std::endl;
}
};
int main()
{
A a; a.f(10.10); // as expected, A.f will get called
B b; b.f(10.10); // This calls b.f and we lose the .10 here
return 0;
}
O meu entendimento foi quando um tipo é herdado, todos os membros protegidas públicas e será acessível a partir da classe derivada. Mas de acordo com este exemplo, parece que eu estou errado. Eu estava esperando o b.f irá chamar classes base f . Eu tenho o resultado esperado, alterando a classe derivada como
struct B : A
{
using A::f;
void f(int)
{
std::cout << "in int" << std::endl;
}
};
Perguntas
- Por que não era trabalhar no primeiro código?
- Qual a secção do C ++ padrão descreve todas estas regras de escopo?
Solução
O primeiro código funciona como c ++ é projetado para trabalho.
A sobrecarga resolução segue um conjunto muito complicado de regras. De c do Stroustrup ++ bíblia 15.2.2 "[A] mbiguities entre as funções de diferentes classes de base não são resolvidos com base em tipos de argumentos."
Ele passa a explicar o uso de "usar", como você descreveu.
Esta foi uma decisão de projeto na língua.
I tendem a seguir o livro Stroustrup, em vez do padrão, mas eu tenho certeza que ele está lá.
[Edit]
Aqui está (do padrão):
Capítulo 13
Quando são especificados dois ou mais diferentes declarações para um único nome no mesmo escopo, esse nome é dito ser sobrecarregado.
E, em seguida:
13.2 Declaração de harmonização
1 Duas declarações de função com o mesmo nome referem-se a mesma função se eles estão no mesmo escopo e têm declarações de parâmetros equivalentes (13,1). Um membro função de uma classe de derivados não está no mesmo alcance como um membro de função o mesmo nome em uma classe base.
Outras dicas
É porque A :: f é "escondido" em vez de "sobrecarga" ou "substituído". Consulte:
http://www.parashift.com /c++-faq-lite/strange-inheritance.html#faq-23.9
Pesquise resolução sobrecarga . A semelhante, mas não .
C ++, não há sobrecarga através de espaços, no escopo classes derivadas não são uma excepção. (segundo a C ++ Programming Language)
Para obter mais informações, consulte a http: //www.research. att.com/~bs/bs_faq2.html#overloadderived
No primeiro caso, o método da classe base 'f' é escondida pelo método de classe derivada. Em C ++ não há sobrecarga através âmbitos; é por isso que não é chamado. O padrão C ++ explica todas as regras o nome do membro de pesquisa do seção 10.2 Membro pesquisa de nome [class.member.lookup] . HTH
A primeira versão do código deve realmente chamar B :: f. Você re-definir o símbolo "f" em struct "B", por isso esconde o símbolo original "f" do struct "A". Não é uma sobrecarga, como pode parecer.
Sempre que compilador encontra b.f (), ele procura o struct "B" para um símbolo de "f". Ela está presente lá, então o compilador decide chamar B :: f (int), convertendo duplo para int. Ele não vê necessidade de digitalizar a classe pai para uma função mais adequada ...
No entanto, quando você adicionar "usando Um :: f", é uma directiva explict para o compilador para digitalizar uma classe pai para o símbolo "f". Agora, a classe B tem duas funções sobrecarregadas:. Para int e para double
Acredito também, que você pode escrever B. De :: f () sem usar "usando" directiva no exemplo original ...