Вложенные классы: доступ к защищенному члену входящего класса из вложенного защищенного класса

Этот код компилируется на msvc/g++:

class A{
protected:
    int i;
    class B{
    public:
        A* a;
        B(A* a_)
        :a(a_){
        }
        void doSomething(){
            if (a)
                a->i = 0;//<---- this part
        }       
    };
public:
    A()
    :i(0){
    }
};

Как вы можете видеть, B получает доступ к "защищенному" разделу охватывающего класса, хотя он не объявляется как друг.

Является ли это стандартным (стандартно-совместимым) поведением?

Я иногда использую эту функцию, но я не помню правила о том, что вложенный защищенный класс должен автоматически получить доступ ко всем защищенным данным окружающего класса.

Ответы

Ответ 1

В стандарте С++ 03, 11.8p1 говорит:

Члены вложенного класса не имеют специального доступа к членам охватывающего класса.

Тем не менее, разрешение для отчета о дефектах 45 (до стандарта) указывает противоположное и, следовательно, определяет поведение, которое вы видите:

Вложенный класс является членом и как таковой имеет те же права доступа, что и любой другой член.

В С++ 0x текст 11.8 был изменен, чтобы отразить этот факт, поэтому это допустимое поведение как для компиляторов С++ 03, так и для С++ 0x.

См. также этот поток из cprogramming.com форум.

Ответ 2

У меня нет копии С++ 03, но из черновика (n3090) С++ 0x:

11.8 Вложенные классы

1 Вложенный класс является членом и как таковой имеет тот же права доступа как любой другой член. члены закрывающего класса не имеют специальный доступ к членам вложенного класс; обычные правила доступа (пункт 11).

[Пример:

class E {
    int x;
    class B { };
    class I {
        B b; // OK: E::I can access E::B
        int y;
        void f(E* p, int i) {
            p->x = i; // OK: E::I can access E::x
        }
    };
    int g(I* p) {
        return p->y; // error: I::y is private
    }
};

Итак, по крайней мере, в следующем стандарте закрытые классы могут обращаться к членам внешнего класса, как и любая нормальная функция-член.

Обновление: Это не разрешено в текущем стандарте. Но для исправления был отправлен отчет о дефекте (DR 45). (Редактирование SigTerm получило это. Пожалуйста, будьте осторожны.)

Обновление # 2: я попытался с VS2010, g++ (4.0.1 Apple) с -Wall -ansi -pedantic -std=c++98 и Comeau (4.3.10.1) в строгом режиме С++ 03 с отключенными расширениями С++ 0x - все они кажутся принимать доступ к внешним классам private во внутренних членах класса.

Ответ 3

Обратитесь за $9.7/1.

"Вложенный класс находится в области его охватывающего класса. За исключением использования явных указателей, ссылок и имен объектов объявления в вложенном классе могут использовать только имена типов, статические элементы и счетчики из охватывающего класса. "

Ответ 4

Является ли это стандартным (стандартно-совместимым) поведением?

Нет.

В соответствии с С++ - 2003

Section 11.8.1

Вложенные классы

Члены вложенного класса не имеют специального доступа к членам охватывающего класса, а также к классам или функциям, которые предоставили дружбу окружающему классу; должны соблюдаться обычные правила доступа (пункт 11). Члены закрывающего класса не имеют специального доступа к членам вложенного класса; должны соблюдаться обычные правила доступа (пункт 11).

[Example:
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
    }
};
—end example]

Но есть небольшая модификация этого раздела в ISO/IEC N 3092, в котором говорится

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