Чи можуть внутрішні класи отримати доступ до приватних змінних?


117
class Outer {

    class Inner {
    public:
        Inner() {}
        void func() ;
    };

private:
    static const char* const MYCONST;
    int var;
};

void Outer::Inner::func() {
    var = 1;
}

const char* const Outer::MYCONST = "myconst";

Ця помилка виходить, коли я компілюю з класом Зовнішній :: Внутрішній 'не має члена з ім'ям `var'

Відповіді:


120

Внутрішній клас є другом класу, якого він визначає.
Отже, так; об’єкт типу Outer::Innerможе отримати доступ до змінної члена varоб'єкта типу Outer.

На відміну від Java, немає кореляції між об'єктом типу Outer::Innerта об'єктом батьківського класу. Ви повинні скласти стосунки батьків з дітьми вручну.

#include <string>
#include <iostream>

class Outer
{
    class Inner
    {
        public:
            Inner(Outer& x): parent(x) {}
            void func()
            {
                std::string a = "myconst1";
                std::cout << parent.var << std::endl;

                if (a == MYCONST)
                {   std::cout << "string same" << std::endl;
                }
                else
                {   std::cout << "string not same" << std::endl;
                }
            }
        private:
            Outer&  parent;
    };

    public:
        Outer()
            :i(*this)
            ,var(4)
        {}
        Outer(Outer& other)
            :i(other)
            ,var(22)
        {}
        void func()
        {
            i.func();
        }
    private:
        static const char* const MYCONST;
        Inner i;
        int var;
};

const char* const Outer::MYCONST = "myconst";

int main()
{

    Outer           o1;
    Outer           o2(o1);
    o1.func();
    o2.func();
}

14
Технічно в поточному стандарті C ++ вкладений клас НЕ має спеціального доступу до свого класу, що охоплює. Див. Розділ 11.8.1 стандарту. ЯКЩО дивіться також цей стандартний дефект: open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45
Грег Роджерс

1
Чого варто, GCC дотримується запропонованої там резолюції, ймовірно, це роблять і інші компілятори.
Грег Роджерс

24
Стандарт C + 11 тепер відповідає вищеописаному опису.
Мартін Йорк

1
У Java нестатичному внутрішньому класу неявно надається посилання (покажчик) на екземпляр його зовнішнього класу, коли до внутрішнього класу звертається вперше. Перефразовуючи це, jvm неявно пише код для вас, схожий на те, що @LokiAstari показав нам у своїй відповіді. Ось уривок з Ефективної Java 2nd Ed "Пункт 22: Вигідні статичні класи членів над нестатичними": "Якщо ви опустите цей модифікатор (статичне ключове слово при оголошенні внутрішнього класу), кожен екземпляр матиме сторонні посилання на свій примірник, що вкладається".
Девід Лі

3
@Loki Astari: Я прочитав останнє речення "Ви повинні скласти стосунки батьків з дітьми вручну" і інтерпретував фрагмент коду, який випливав із прикладу того, як це зробити правильно !
Brent Baccala

32

Внутрішній клас має доступ до всіх членів зовнішнього класу, але він не має явної посилання на екземпляр батьківського класу (на відміну від деяких дивацтв з Java). Отже, якщо ви передаєте посилання на зовнішній клас до внутрішнього класу, він може посилатися на що завгодно в екземплярі зовнішнього класу.


7
це правда від c ++ 11
thrantir

6

Все, що є частиною Зовнішньої, повинно мати доступ до всіх членів Зовнішніх, державних чи приватних.

Редагувати: ваш компілятор правильний, var не є членом Inner. Але якщо у вас є посилання або вказівник на екземпляр Зовнішній, він може отримати доступ до цього.


2

var не є членом внутрішнього класу.

Для доступу до var слід використовувати вказівник або посилання на екземпляр зовнішнього класу. наприклад, pOuter-> var буде працювати, якщо внутрішній клас є другом зовнішнього, або, var є загальнодоступним, якщо суворо слідкувати стандарт C ++.

Деякі укладачі ставляться до внутрішніх класів як до друга зовнішніх, але деякі можуть. Дивіться цей документ для компілятора IBM :

"Вкладений клас оголошено в межах іншого класу. Ім’я вкладеного класу є локальним для класу, що вкладається. Якщо ви не використовуєте явні вказівники, посилання або назви об'єктів, у деклараціях вкладеного класу можна використовувати лише видимі конструкції, в т.ч. назви типів, статичні члени та нумератори із класу, що додається, та глобальних змінних.

Функції учасників вкладеного класу дотримуються правил регулярного доступу та не мають спеціальних привілеїв доступу для членів їх класів, що додаються. Функції учасників класу, що вкладається, не мають спеціального доступу до членів вкладеного класу. "


4
Неправильно. Дивіться інші відповіді - на 3 роки раніше. "якщо суворо слідкувати за стандартом C ++", вони отримують різні відповіді від ваших. На початку проекту для C ++ 11 вкладені класи можуть отримати доступ до всіх членів батьків через посилання / покажчик. Немає вимоги чітко заявляти friendабо public. Кого хвилює, чи раніше IBM помилився / застарів, у мертвій ланці? Ця відповідь була застаріла за 3 роки до її опублікування.
підкреслюй_

1

Перш за все, ви намагаєтеся отримати доступ до нестатичного члена varпоза класом, який заборонено в C ++.

Відповідь Марка правильна.

Все, що є частиною Зовнішньої, повинно мати доступ до всіх членів Зовнішніх, державних чи приватних.

Таким чином, ви можете зробити дві речі, або оголосити varяк staticабо використовувати посилання на екземпляр зовнішнього класу для доступу до "var" (оскільки для доступу до приватних даних потрібен також посилання на клас друзів або функцію ).

Статичний вар

Змінити varна staticЯкщо ви не хочете varасоціюватися з екземплярами класу.

#include <iostream>

class Outer {

private:
    static const char* const MYCONST;
    static int var;

public:
   class Inner {
    public:
        Inner() {
          Outer::var = 1;
        }
        void func() ;
    };
};

int Outer::var = 0;

void Outer::Inner::func() {
    std::cout << "var: "<< Outer::var;
}

int main() {
  Outer outer;
  Outer::Inner inner;
  inner.func();

}

Вихідні показники: 1

Нестатична вар

Посилання на об'єкт має мати доступ до будь-яких нестатичних змінних членів.

#include <iostream>

class Outer {

private:
    static const char* const MYCONST;
    int var;

public:
   class Inner {
    public:
        Inner(Outer &outer) {
          outer.var = 1;
        }
        void func(const Outer &outer) ;
    };
};

void Outer::Inner::func(const Outer &outer) {
    std::cout << "var: "<< outer.var;
}

int main() {
  Outer outer;
  Outer::Inner inner(outer);
  inner.func(outer);

}

Вихідні показники: 1

Редагувати - зовнішні посилання - це посилання на мій блог.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.