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 método 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 então adiciono um método, e meu código de trabalho não compila de forma alguma.
Respostas:
Quando você chama
a.foo();
, o compilador passa pela resolução de sobrecarga para encontrar a melhor função a ser usada. Quando ele constrói o conjunto de sobrecarga, ele encontrae
Agora, como
a
não éconst
, a versão não const é a melhor combinação, então o compilador escolhevoid foo()
. Em seguida, as restrições de acesso são colocadas em prática e você obtém um erro do compilador, poisvoid foo()
é privado.Lembre-se, na resolução de sobrecarga não é 'encontrar a melhor função utilizável'. É 'encontre a melhor função e tente usá-la'. Se não puder por causa de restrições de acesso ou exclusão, você receberá um erro do compilador.
Bem, vamos olhar para:
Agora, digamos que eu realmente não pretendesse tornar
void foo(Derived * d)
privado. Se o controle de acesso viesse primeiro, este programa seria compilado, executado eBase
impresso. Isso pode ser muito difícil de rastrear em uma grande base de código. Como o controle de acesso vem após a resolução de sobrecarga, recebo um bom erro do compilador informando que a função que desejo que ele chame não pode ser chamada e posso encontrar o bug com muito mais facilidade.fonte
Em última análise, isso se resume à afirmação na norma de que a acessibilidade não deve ser levada em consideração ao executar a resolução de sobrecarga . Esta afirmação pode ser encontrada na cláusula 3 [over.match] :
e também a Nota na cláusula 1 da mesma seção:
Quanto ao motivo, posso pensar em algumas motivações possíveis:
fonte
Suponha que o controle de acesso venha antes da resolução de sobrecarga. Efetivamente, isso significaria
public/protected/private
visibilidade controlada em vez de acessibilidade.A Seção 2.10 de Design e Evolução de C ++ por Stroustrup tem uma passagem onde ele discute o seguinte exemplo
Stroustrup menciona que um benefício das regras atuais (visibilidade antes da acessibilidade) é que (temporariamente)
private
entrarclass X
no interiorpublic
(por exemplo, para fins de depuração) é que não há nenhuma mudança silenciosa no significado do programa acima (ou seja,X::a
é tentado ser acessado em ambos os casos, o que dá um erro de acesso no exemplo acima). Sepublic/protected/private
controlasse a visibilidade, o significado do programa mudaria (globala
seria chamado comprivate
, caso contrárioX::a
).Ele então afirma que não se lembra se foi por design explícito ou um efeito colateral da tecnologia de pré-processador usada para implementar o C com o predecessor Classess para C ++ Padrão.
Como isso está relacionado ao seu exemplo? Basicamente porque o padrão fez a resolução de sobrecarga estar em conformidade com a regra geral de que a pesquisa de nomes vem antes do controle de acesso.
fonte
Visto que o
this
ponteiro implícito é não-const
, o compilador primeiro verificará a presença de uma não-const
versão da função antes de umaconst
versão.Se você marcar explicitamente o não-
const
umprivate
, a resolução falhará e o compilador não continuará pesquisando.fonte
É importante ter em mente a ordem das coisas que acontecem, que é:
delete
d), falhe.(3) acontece depois de (2). O que é muito importante, porque, de outra forma, criar funções
delete
d ouprivate
ficaria meio sem sentido e muito mais difícil de raciocinar.Nesse caso:
A::foo()
eA::foo() const
.A::foo()
porque a última envolve uma conversão de qualificação nothis
argumento implícito .A::foo()
éprivate
e você não tem acesso a ele, portanto, o código está mal formado.fonte
Isso se resume a uma decisão de design bastante básica em C ++.
Ao pesquisar a função para satisfazer uma chamada, o compilador realiza uma pesquisa como esta:
Ele pesquisa para encontrar o primeiro 1 escopo no qual há algo com esse nome.
O compilador encontra todas as funções (ou functores, etc.) com aquele nome naquele escopo.
Em seguida, o compilador sobrecarrega a resolução para encontrar o melhor candidato entre aqueles que encontrou (sejam eles acessíveis ou não).
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 está acessível, embora haja outra sobrecarga que está acessível (mas não escolhida durante a resolução da sobrecarga).
Sobre se seria possível fazer diferente: sim, sem dúvida é possível. Isso definitivamente levaria a uma linguagem bastante diferente do C ++. Acontece que muitas decisões aparentemente menores podem ter ramificações que afetam muito mais do que seria inicialmente óbvio.
fonte
Controles de acesso (
public
,protected
,private
) não afetam sobrecarga resolução. O compilador escolhevoid foo()
porque é a melhor combinação. O fato de não ser acessível não muda isso. Removê-lo deixa apenasvoid foo() const
, que é a melhor (ou seja, única) correspondência.fonte
Nesta chamada:
Sempre há um
this
ponteiro implícito disponível em cada função de membro. E aconst
qualificação dethis
é retirada da referência / objeto de chamada. A chamada acima é tratada pelo compilador como:Mas você tem duas declarações das
A::foo
quais são tratadas como :Por resolução de sobrecarga, o primeiro será selecionado para não const
this
, o segundo será selecionado para aconst this
. Se você remover o primeiro, o segundo se ligará a ambosconst
enon-const
this
.Após a resolução da sobrecarga 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 isso:
Mas se você fizer isso:
Então, apenas a
const
sobrecarga será adequada.fonte
A razão técnica foi respondida por outras respostas. Vou me concentrar apenas nesta questão:
É 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 projeto novamente.
Por outro lado, suponha que seu código compilado e
const
funcione bem com a função de membro que está sendo chamada. Algum dia, alguém (talvez você) decide alterar a acessibilidade daconst
função de não membro deprivate
parapublic
. Então, o comportamento mudaria sem erros de compilação! Isso seria uma surpresa .fonte
Porque a variável
a
namain
função não é declarada comoconst
.Funções-membro constantes são chamadas em objetos constantes.
fonte
Os especificadores de acesso não afetam a pesquisa de nome e a resolução de chamada de função, nunca. A função é selecionada antes que o compilador verifique 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 for levada em consideração para a resolução da chamada de função, o comportamento do seu programa pode mudar silenciosamente.
fonte