вопрос о приоритетности операторов С ++ «адрес» и «разрешение области» - PullRequest
23 голосов
/ 16 февраля 2011

Здравствуйте, у меня есть этот код с ошибкой компилятора (ошибка из 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'
};

пока этот код не содержит ошибок:

class B
{
protected:
int b;
};

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

Эти два фрагмента кажутся мне эквивалентными, основываясь на моих знаниях о приоритетности операторов, потому что :: имеет более высокий приоритет, чем & (см., Например, таблицу 2 на стр. 137 "СТАНДАРТОВ КОДИРОВАНИЯ ВОЗДУШНОГО АВТОМОБИЛЯ БОРЬБЫ С БОИМИ С ++ ПРОГРАММА РАЗВИТИЯ И ДЕМОНСТРАЦИИ СИСТЕМЫ "http://www2.research.att.com/~bs/JSF-AV-rules.pdf)

Но они разные ... Я думаю, что это что-то, связанное с "указателем на член-данные", но я не знаю, как это согласуется с приоритетом операторов.

Любое объяснение?

Спасибо, Alessandro

Ответы [ 3 ]

13 голосов
/ 16 февраля 2011

В первом случае вы берете адрес указателя на член B::b.Поскольку такой указатель НЕ является членом родительского элемента A, а является отдельным объектом, он не может получить к нему доступ через защищенный механизм.

В ВТОРОМ случае, когда он работает, вы запрашиваетеадрес конкретного экземпляра из b с указанием его базового класса, чтобы в случае множественного наследования компилятор знал, какой базовый класс вы имеете в виду.В этом контексте защищенный атрибут виден.

Обратите внимание, что это компилируется:

class B
{
protected:
int b;
};

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

В качестве дополнительного примера он не работает по той же причине, что и следующая (надеюсь, более знакомая)код не работает:

class B
{
protected:
int b;
};

class A : public B
{
public:
void foo(const B* b_obj) { b_obj->b; }
};
7 голосов
/ 16 февраля 2011

Это просто добавка.
§5.3.1 / 2 говорит:

Результат унарного оператора & указатель на его операнд. Операнд должен быть lvalue или квалифицированным идентификатором. В первом случае, если тип выражение «Т», тип Результатом является «указатель на T.» ...
Для квалифицированный идентификатор, ... Если участник нестатический член класса C типа T, тип результата «указатель представителю класса C типа T ".

Согласно §5.1 / 7, B::b относится к случаю квалифицированного идентификатора, но (B::b) нет. Таким образом, компилятор интерпретирует его как lvalue.

6 голосов
/ 16 февраля 2011

Различие между двумя операторами становится более очевидным, когда вы пытаетесь вернуть значение:

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

То, что вы хотите сделать, это получить к нему доступ через объект A:

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

Начиная с A, вам разрешен доступ к нему.
Доступ к нему через B аналогичен обращению извне и, таким образом, вызывает спецификаторы доступа.

...