Подтвердить что ты не робот

Вопрос о приоритете операторов С++ "адрес" и "разрешение области",

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

4b9b3361

Ответ 1

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

В SECOND случае, когда он работает, вы запрашиваете адрес конкретного экземпляра 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; }
};

Ответ 2

Это просто дополнение.
В §5.3.1/2 говорится:

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

В соответствии с § 5.1/7, B::b попадает в case-id, но (B::b) - нет. Таким образом, компилятор интерпретирует его как lvalue.

Ответ 3

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

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, как и доступ к нему, осуществляется извне и, таким образом, запускает спецификаторы доступа.