Dominância (C ++) - Dominance (C++)
Na ++ C linguagem de programação, o domínio refere-se a um aspecto particular de C ++ pesquisa de nome na presença de herança . Quando o compilador calcula o conjunto de declarações a que um determinado nome pode se referir, declarações nas aulas de muito ancestrais que são "dominadas" por declarações nas classes menos ancestrais estão escondidos para fins de pesquisa de nome. Em outras linguagens ou contextos, o mesmo princípio pode ser referido como " mascaramento nome " ou " sombra ".
O algoritmo para calcular a pesquisa de nome é descrito na secção 10.2 [class.member.lookup] do C ++ 11 padrão. A descrição do padrão não usa a palavra "dominância", preferindo descrever as coisas em termos de conjuntos de declaração e esconderijo . No entanto, o índice contém uma entrada para "dominância, classe base virtual" referindo-se a seção 10.2.
Conteúdo
Exemplo sem herança diamante
void f(double, double); // at global scope
struct Grandparent {
void f(int);
void f(double, double);
};
struct Parent : public Grandparent {
void f(int); // hides all overloads of Grandparent::f
};
struct Child : public Parent {
void g() { f(2.14, 3.17); } // resolves to Parent::f
};
No exemplo acima, Child::g
contém uma referência ao nome f
. No entanto, o programa como um todo contém quatro declarações do nome f
. A fim de descobrir o que f
se quer dizer, o compilador calcula um conjunto de sobrecarga contendo todas as declarações que não estão escondidos no ponto da chamada. A declaração de f
no escopo global está oculta por Grandparent::f
, e por sua vez Grandparent::f
está oculta por Parent::f
. Assim, a única declaração que é considerado por resolução de sobrecarga é Parent::f
- eo resultado, neste caso, é um diagnóstico, porque a chamada local oferece dois argumentos em que Parent::f
espera apenas uma.
Muitas vezes, é surpreendente para novos programadores C ++ que a declaração de Parent::f
domina e esconde tudo das declarações mais-ancestrais, independentemente da assinatura; isto é, Parent::f(int)
domina e esconde a declaração de Grandparent::f(double, double)
, apesar das duas funções membro tem muito diferentes assinaturas.
É também importante observar que, no C ++, a pesquisa de nome precede a resolução de sobrecarga . Se Parent::f
teve várias sobrecargas (por exemplo, f(int)
e f(double, double)
), o compilador iria escolher entre eles em tempo de sobrecarga-resolução; mas durante a fase de nome-lookup estamos preocupados apenas com a escolha entre os três escopos Grandparent::f
, Parent::f
e ::f
. O fato de que Grandparent::f(double, double)
teria sido uma melhor sobrecarga que f(int)
não faz parte da consideração do compilador.
Exemplo herança com diamante
struct Grandparent {
void f(int);
void f(double, double);
};
struct Mother : public Grandparent {
void f(int); // hides all overloads of Mother::Grandparent::f
};
struct Father : public Grandparent { };
struct Child : public Mother, Father { // Mother::Grandparent is not the same subobject as Father::Grandparent
void g() { f(2.14, 3.17); } // ambiguous between Mother::f and Father::Grandparent::f
};
No exemplo acima, o compilador calcula um conjunto de sobrecarga para f
que contém ambos Mother::f
e Father::Grandparent::f
. O compilador produz um diagnóstico indicando que o programa está mal formada porque o nome f
é ambíguo .
Exemplo com herança virtual
struct Grandparent {
void f(int);
void f(double, double);
};
struct Mother : public virtual Grandparent {
void f(int); // hides all overloads of Mother::Grandparent::f
};
struct Father : public virtual Grandparent { };
struct Child : public Mother, Father { // Mother::Grandparent is the same subobject as Father::Grandparent
void g() { f(2.14, 3.17); } // resolves to Mother::f
};
Neste último exemplo, o nome f
mais uma vez de forma inequívoca refere-se Mother::f
, porque Mother::f
esconde o f
declarou em seu Grandparent
sub-objeto. The Standard chama neste caso surpreendente em um informativo nota (§10.2 parágrafo 10):
Quando classes base virtuais são usados, uma declaração escondido pode ser alcançado por um caminho através da grade subobject que não passa através da declaração esconderijo. Esta não é uma ambigüidade.
Mesmo que Child
em si eram de herdar virtualmente a partir Grandparent
, não haveria nenhuma ambiguidade na pesquisa de nome. No entanto, se Child
fosse para herdar não -virtually de Grandparent
(ou seja, struct Child : public Mother, Father, Grandparent
), o nome seria novamente ambiguated (entre as f
s declarada nos dois Grandparent
subobjects).
Veja também
Referências
- ^ Um b Projecto N3797 Trabalho, Norma para linguagem de programação C ++ . Datado de 2013/10/13.