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.

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::gconté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 fse 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 fno escopo global está oculta por Grandparent::f, e por sua vez Grandparent::festá 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::fespera apenas uma.

Muitas vezes, é surpreendente para novos programadores C ++ que a declaração de Parent::fdomina 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::fteve 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::fe ::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 fque contém ambos Mother::fe 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 fmais uma vez de forma inequívoca refere-se Mother::f, porque Mother::fesconde o fdeclarou em seu Grandparentsub-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 Childem si eram de herdar virtualmente a partir Grandparent, não haveria nenhuma ambiguidade na pesquisa de nome. No entanto, se Childfosse para herdar não -virtually de Grandparent(ou seja, struct Child : public Mother, Father, Grandparent), o nome seria novamente ambiguated (entre as fs declarada nos dois Grandparentsubobjects).

Veja também

Referências