uma pergunta sobre a precedência em C++, os operadores "endereço de" e "de resolução de escopo"

StackOverflow https://stackoverflow.com/questions/5018603

Pergunta

Olá eu tenho esse código com um compilador de erro (erro do Microsoft Visual Studio 2008):

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(){ &B::b; }//  error C2248: 'B::b' : cannot access protected member declared in class 'B'
};

enquanto esse código é livre de erro:

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(){ &(B::b); }
};

Os dois trechos me parecem equivalentes, com base no meu conhecimento de precedência de operadores, porque ::tem uma precedência superior & (ver, por exemplo, a tabela 2 na página 137 de "JOINT STRIKE FIGHTER VEÍCULO AÉREO C++ PADRÕES de CODIFICAÇÃO PARA O SISTEMA de DESENVOLVIMENTO E PROGRAMA de DEMONSTRAÇÃO" http://www2.research.att.com/~bs/JSF-AV-regras.pdf )

Mas eles são diferentes...Eu acho que é algo relacionado com a "ponteiro-para-dados-membro", mas eu não sei como ele se enquadra com os operadores precedência.

Alguma explicação?

Obrigado, Alessandro

Foi útil?

Solução

No primeiro caso, você está tomando o endereço do ponteiro-para-membro B::b.Uma vez que tal um ponteiro NÃO é um membro do principal da A mas um objeto separado, ele não pode acessá-lo através do mecanismo protegido.

No SEGUNDO caso, onde ele funciona, você está pedindo para o endereço do instância específica de b, qualificando-o com a sua base de classe para que, no caso de herança múltipla para o compilador saber que a base de classe média.Neste contexto, o atributo protegido é visível.

Note que este compila:

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(){ &A::b; }  // Note here &A:: instead of &B::
};

Como um exemplo, ele não funcionar pela mesma razão que o seguinte (espero que mais familiar), de código não funciona:

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(const B* b_obj) { b_obj->b; }
};

Outras dicas

Este é apenas um suplemento.
§5.3.1/2 diz:

O resultado da unário & operador um ponteiro para seu operando.O operando deve ser um lvalue ou qualificada-id.No primeiro caso, se o tipo de a expressão é "T", o tipo da o resultado é "ponteiro para T." ...
Para um qualificado-id, ...Se o membro for um não-membro estático da classe C, do tipo T, o tipo do resultado é "ponteiro para o membro da classe C, do tipo T."

De acordo com o parágrafo 5.1/7, B::b vem sob o qualificado-identificação do caso, mas (B::b) não.Assim, o compilador interpreta como um lvalue.

O differece entre as duas declarações se torna mais evidente quando você tentar retornar o valor:

int*     foo()    { return &(B::b);}  // This is a pointer to an int


int A::* foo()    { return &B::b; }   // This is a pointer to a member of type int

O que você quer fazer é aceder a ele através de Um objeto:

int A::* foo()    { return &A::b; }   // This is a pointer to a member of type int

Como de Um você tem permissão para acessá-lo.
Acessando-o através de B, como a que está a aceder à mesma a partir de fora e, assim, desencadeia o acesso especificadores.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top