define - operator overloading c++ geeksforgeeks



Por que um método const público não é chamado quando o não-const é privado? (8)

É importante ter em mente a ordem das coisas que acontecem, que é:

  1. Encontre todas as funções viáveis.
  2. Escolha a melhor função viável.
  3. Se não houver exatamente uma melhor viável, ou se você realmente não puder chamar a melhor função viável (devido a violações de acesso ou à delete da função d), falhe.

(3) acontece depois de (2). O que é realmente importante, porque, caso contrário, tornar as funções delete d ou private se tornaria meio sem sentido e muito mais difícil de se pensar.

Nesse caso:

  1. As funções viáveis ​​são A::foo() e A::foo() const .
  2. A melhor função viável é A::foo() porque esta envolve uma conversão de qualificação no argumento implícito.
  3. Mas A::foo() é private e você não tem acesso a ele; portanto, o código está mal formado.

Considere este código:

struct A
{
    void foo() const
    {
        std::cout << "const" << std::endl;
    }

    private:

        void foo()
        {
            std::cout << "non - const" << std::endl;
        }
};

int main()
{
    A a;
    a.foo();
}

O erro do compilador é:

erro: 'void A :: foo ()' é privado`.

Mas quando eu excluo o privado, ele simplesmente funciona. Por que o método const público não é chamado quando o não-const é privado?

Em outras palavras, por que a resolução de sobrecarga vem antes do controle de acesso? Isto é estranho. Você acha que é consistente? Meu código funciona e, em seguida, adiciono um método, e meu código de trabalho não é compilado.


Answer #1

Como o ponteiro implícito é não- const , o compilador primeiro verificará a presença de uma versão não- const da função antes de uma versão const .

Se você marcar explicitamente o não- const private , a resolução falhará e o compilador não continuará pesquisando.


Answer #2

Isso se resume a uma decisão de design bastante básica em C ++.

Ao procurar a função para satisfazer uma chamada, o compilador realiza uma pesquisa como esta:

  1. Ele procura encontrar o primeiro escopo no qual existe algo com esse nome.

  2. O compilador encontra todas as funções (ou functors, etc.) com esse nome nesse escopo.

  3. Em seguida, o compilador sobrecarrega a resolução para encontrar o melhor candidato dentre os encontrados (estejam eles acessíveis ou não).

  4. Finalmente, o compilador verifica se a função escolhida está acessível.

Por causa dessa ordem, sim, é possível que o compilador escolha uma sobrecarga que não seja acessível, mesmo que haja outra sobrecarga que seja acessível (mas não escolhida durante a resolução de sobrecarga).

Se seria possível fazer as coisas de maneira diferente: sim, é sem dúvida possível. Definitivamente, isso levaria a uma linguagem bem diferente da C ++. Acontece que muitas decisões aparentemente menores podem ter ramificações que afetam muito mais do que seria inicialmente óbvio.

  1. O "primeiro" pode ser um pouco complexo por si só, especialmente quando / se os modelos se envolverem, pois podem levar à pesquisa em duas fases, o que significa que existem duas "raízes" totalmente separadas para iniciar a pesquisa. A idéia básica é bem simples: comece pelo menor escopo de fechamento e vá até escopos de fechamento cada vez maiores.

Answer #3

Nesta chamada:

a.foo();

Sempre há um ponteiro implícito disponível em todas as funções de membro. E a qualificação const this é obtida da referência / objeto que está chamando. A chamada acima é tratada pelo compilador como:

A::foo(a);

Mas você tem duas declarações de A::foo que são tratadas como :

A::foo(A* );
A::foo(A const* );

Por resolução de sobrecarga, o primeiro será selecionado para não const, o segundo será selecionado para um const this . Se você remover o primeiro, o segundo será vinculado a const e non-const this .

Após a sobrecarga de resolução para selecionar a melhor função viável, vem o controle de acesso. Como você especificou o acesso à sobrecarga escolhida como private , o compilador irá reclamar.

O padrão diz o seguinte:

[class.access/4] : ... No caso de nomes de função sobrecarregados, o controle de acesso é aplicado à função selecionada por resolução de sobrecarga ....

Mas se você fizer isso:

A a;
const A& ac = a;
ac.foo();

Então, apenas a sobrecarga const será adequada.


Answer #4

Os especificadores de acesso nunca afetam a pesquisa de nomes e a resolução de chamadas de funções. A função é selecionada antes do compilador verificar se a chamada deve acionar uma violação de acesso.

Dessa forma, se você alterar um especificador de acesso, será alertado em tempo de compilação se houver uma violação no código existente; se a privacidade fosse levada em consideração para a resolução de chamadas de função, o comportamento do seu programa poderia mudar silenciosamente.


Answer #5

Porque a variável a na função main não é declarada como const .

Funções de membro constantes são chamadas em objetos constantes.


Answer #6

Suponha que o controle de acesso veio antes da resolução de sobrecarga. Efetivamente, isso significaria visibilidade public/protected/private controlada em vez de acessibilidade.

Seção 2.10 de Design e evolução de C ++ por Stroustrup tem uma passagem sobre isso, onde ele discute o exemplo a seguir

int a; // global a

class X {
private:
    int a; // member X::a
};

class XX : public X {
    void f() { a = 1; } // which a?
};

Stroustrup menciona que um benefício das regras atuais (visibilidade antes da acessibilidade) é que (temporariamente) perseguir o private dentro da class X para o public (por exemplo, para fins de depuração) é que não há uma mudança silenciosa no significado do programa acima ( isto é, tenta-se acessar o X::a a nos dois casos, o que gera um erro de acesso no exemplo acima). Se public/protected/private controlasse a visibilidade, o significado do programa mudaria (a global seria chamado com private , caso contrário, X::a ).

Ele então afirma que não se lembra se foi por design explícito ou por um efeito colateral da tecnologia de pré-processador usada para implementar o C com o predecessor Classess no Standard C ++.

Como isso está relacionado ao seu exemplo? Basicamente, porque o Padrão estabeleceu uma resolução de sobrecarga em conformidade com a regra geral de que a pesquisa de nome vem antes do controle de acesso.

10.2 Pesquisa de nome de membro [class.member.lookup]

1 A pesquisa de nome de membro determina o significado de um nome (expressão id) em um escopo de classe (3.3.7). A pesquisa de nome pode resultar em uma ambiguidade, caso em que o programa está mal formado. Para uma expressão id, a pesquisa de nome começa no escopo da classe; para um ID qualificado, a pesquisa de nome começa no escopo do especificador de nome nested. A pesquisa de nome ocorre antes do controle de acesso (3.4, Cláusula 11).

8 Se o nome de uma função sobrecarregada for encontrado sem ambiguidade, a resolução de sobrecarga (13.3) também ocorrerá antes do controle de acesso . As ambiguidades geralmente podem ser resolvidas qualificando um nome com o nome da classe.


Answer #7

O motivo técnico foi respondido por outras respostas. Vou me concentrar apenas nesta questão:

Em outras palavras, por que a resolução de sobrecarga vem antes do controle de acesso? Isto é estranho. Você acha que é consistente? Meu código funciona e, em seguida, adiciono um método e meu código de trabalho não é compilado.

Foi assim que a linguagem foi projetada. A intenção é tentar chamar a melhor sobrecarga viável, na medida do possível. Se falhar, um erro será acionado para lembrá-lo de considerar o design novamente.

Por outro lado, suponha que seu código compilou e funcionou bem com a função de membro const sendo invocada. Algum dia, alguém (talvez você mesmo) decida alterar a acessibilidade da função de membro que não seja const , de private para public . Em seguida, o comportamento mudaria sem erros de compilação! Isso seria uma surpresa .





member-functions