Управление доступом вложенного класса в С++
Может ли внутренний класс получить доступ к частной переменной-члену своего охватывающего класса? Кажется, что есть некоторые противоречия в Интернете и компиляторе. Компиляция (g++ на cygwin) позволяет это. Но некоторые технические документы говорят, что это запрещено.
Ответы
Ответ 1
Эта проблема была рассмотрена в Отчет об ошибках # 10 и Отчет о дефекте № 45.
Оригинальный и текущий стандарт языка С++ не предоставляет вложенным классом дополнительных прав доступа, то есть он не имеет привилегий при доступе к членам охватывающего класса. Вложенные классы - это просто обычные полностью независимые классы, которые просто объявляются внутри какого-либо другого класса.
Но в соответствии с предлагаемой резолюцией в отчете о дефекте № 45 вложенному классу должны быть предоставлены права доступа всем членам охватывающего класса. То есть вложенный класс должен сам считаться членом охватывающего класса и должен пользоваться всеми правами доступа, обычно предоставляемыми членам.
В прошлый раз, когда я проверил, работа над этим дефектом еще не завершена. Некоторые компиляторы уже реализуют то, что, по их мнению, потребует новая спецификация, то есть права на полный доступ к вложенным классам (см. Предлагаемое решение для DR # 45). Некоторые компиляторы придерживаются буквы текущего стандарта. Вот почему вы все еще можете наблюдать некоторую несогласованность между различными компиляторами в отношении прав доступа, предоставляемых вложенным классам.
Ответ 2
Вложенному классу не предоставляется специальный доступ к внешнему классу.
Раздел 11.8-1 стандарта С++ 03 для вложенных классов:
Члены вложенного класса имеют нет специального доступа к членам охватывающий класс, а также классы или функции, которые дали дружбу к охватывающему классу;
class E {
int x;
class B { };
class I {
B b; // error: E::B is private
int y;
void f(E* p, int i)
{
p->x = i; // error: E::x is private
}
};
int g(I* p)
{
return p->y; // error: I::y is private
}
};
Ответ 3
В компиляторах С++ 03 это обычно разрешено, потому что комитет понял, что было бы логично разрешить это, потому что вложенные классы являются членами их охватывающего класса. Поэтому они отредактировали стандарт, чтобы разрешить его для С++ 0x (ну, исправление было выполнено в 2001 году), и эти компиляторы реализуют это редактирование задним числом как часть их реализации С++ 03.
Я пробовал GCC, Comeau и Clang, все из которых позволяют это. Точно по правилам С++ 03 это не допускается, хотя никакой компилятор там строго соблюдает закон.
Ловушки
Если вы хотите объявить вложенный класс как друга, обратите внимание, что сначала нужно объявить класс, а затем поместить объявление друга
class Outer {
friend class Inner; // wrong, refers to ::Inner
class Inner { /* ... */ };
};
class Inner { };
Вам нужно поменять порядок, чтобы сделать это правильно
class Outer {
class Inner { /* ... */ };
friend class Inner; // correct, refers to Outer::Inner
};
Я видел пару кода, которые сделали это неправильно, но это не было замечено, потому что вложенный класс имел доступ в любом случае.
Другая ошибка заключается в том, что не все части Inner
имеют полный доступ к Outer
выше. Только те части, где Outer
считается полностью определенным классом, имеют такой доступ
class Outer {
typedef int type; // private type member
class Inner {
type member; // ill-formed: no access
void f() {
type var; // OK: access
}
};
friend class Inner; // correct, refers to Outer::Inner
};
Чтобы определить member
, вам нужно сначала объявить его, а затем определить
class Outer {
typedef int type; // private type member
class Inner; // forward declaration of Outer::Inner
friend class Inner; // correct, refers to Outer::Inner
class Inner {
type member; // OK: access
void f() {
type var; // OK: access
}
};
};
Чтобы проверить код друзей, вам нужен старый соответствующий компилятор. Comau Online Compiler в версии 4.3.1 BETA 3/1/03 или ниже.
Ответ 4
"Внутренний" (фактически, только вложенный!) класс в С++, совершенно отличный от Java, не имеет особого статуса. Конечно, все, что нужно сделать внешнему классу, это объявить, что вложенный класс a friend
, а затем (как и любой другой класс друзей!) Он получает доступ к частным членам внешнего класса.