Вопрос о приоритете операторов С++ "адрес" и "разрешение области",
Здравствуйте, у меня есть этот код с ошибкой компилятора (ошибка из 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
Ответы
Ответ 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, как и доступ к нему, осуществляется извне и, таким образом, запускает спецификаторы доступа.