Können innere Klassen auf private Variablen zugreifen?

116
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";

Dieser Fehler tritt auf, wenn ich mit der Klasse Outer :: Inner kompiliere. Es gibt kein Mitglied mit dem Namen "var".

kal
quelle

Antworten:

120

Eine innere Klasse ist ein Freund der Klasse, in der sie definiert ist.
Also ja; ein Objekt vom Typ Outer::Innerkann die Elementvariablen zugreifen varein Objekt des Typs Outer.

Im Gegensatz zu Java besteht jedoch keine Korrelation zwischen einem Objekt vom Typ Outer::Innerund einem Objekt der übergeordneten Klasse. Sie müssen die übergeordnete untergeordnete Beziehung manuell herstellen.

#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();
}
Martin York
quelle
13
Technisch gesehen hat eine verschachtelte Klasse im aktuellen C ++ - Standard KEINEN speziellen Zugriff auf ihre einschließende Klasse. Siehe Abschnitt 11.8.1 des Standards. Siehe jedoch auch diesen Standardfehler: open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45
Greg Rogers
1
GCC folgt dem dort gegebenen Beschlussvorschlag, wahrscheinlich auch andere Compiler.
Greg Rogers
24
Der C + 11-Standard entspricht jetzt der obigen Beschreibung.
Martin York
1
In Java erhält die nicht statische innere Klasse beim ersten Zugriff auf die innere Klasse implizit einen Verweis (Zeiger) auf die Instanz ihrer äußeren Klasse. Um dies neu zu formulieren, schreibt jvm implizit einen Code für Sie, der dem ähnelt, was @LokiAstari uns in seiner Antwort gezeigt hat. Hier ist ein Auszug aus Effective Java 2nd Ed "Punkt 22: Bevorzugen Sie statische Elementklassen gegenüber nicht statischen": "Wenn Sie diesen Modifikator (statisches Schlüsselwort beim Deklarieren der inneren Klasse) weglassen, hat jede Instanz einen externen Verweis auf ihre einschließende Instanz".
David Lee
3
@Loki Astari: Ich habe den letzten Satz "Sie müssen die Eltern-Kind-Beziehung manuell herstellen" gelesen und das folgende Codefragment als Beispiel dafür interpretiert, wie man das richtig macht !
Brent Baccala
31

Eine innere Klasse hat Zugriff auf alle Mitglieder der äußeren Klasse, hat jedoch keinen impliziten Verweis auf eine übergeordnete Klasseninstanz (im Gegensatz zu einer gewissen Verrücktheit mit Java). Wenn Sie also einen Verweis auf die äußere Klasse an die innere Klasse übergeben, kann er auf alles in der Instanz der äußeren Klasse verweisen.

MSN
quelle
7
Dies gilt ab C ++ 11
Thrantir
6

Alles, was Teil von Outer ist, sollte Zugang zu allen öffentlichen oder privaten Mitgliedern von Outer haben.

Bearbeiten: Ihr Compiler ist korrekt, var ist kein Mitglied von Inner. Wenn Sie jedoch einen Verweis oder Zeiger auf eine Instanz von Outer haben, kann dieser darauf zugreifen.

Mark Ransom
quelle
2

var ist kein Mitglied der inneren Klasse.

Für den Zugriff auf var sollte ein Zeiger oder eine Referenz auf eine Instanz der äußeren Klasse verwendet werden. zB pOuter-> var funktioniert, wenn die innere Klasse ein Freund der äußeren ist, oder var ist öffentlich, wenn man den C ++ - Standard streng befolgt.

Einige Compiler behandeln innere Klassen als Freund der äußeren, andere möglicherweise nicht. In diesem Dokument finden Sie Informationen zum IBM Compiler :

"Eine verschachtelte Klasse wird im Bereich einer anderen Klasse deklariert. Der Name einer verschachtelten Klasse ist lokal für die einschließende Klasse. Sofern Sie keine expliziten Zeiger, Verweise oder Objektnamen verwenden, können Deklarationen in einer verschachtelten Klasse nur sichtbare Konstrukte verwenden, einschließlich Geben Sie Namen, statische Elemente und Enumeratoren aus der einschließenden Klasse und den globalen Variablen ein.

Mitgliedsfunktionen einer verschachtelten Klasse folgen regulären Zugriffsregeln und haben keine besonderen Zugriffsrechte für Mitglieder ihrer umschließenden Klassen. Mitgliedsfunktionen der einschließenden Klasse haben keinen besonderen Zugriff auf Mitglieder einer verschachtelten Klasse. "

xiaochuanQ
quelle
4
Falsch. Siehe andere Antworten - 3 Jahre zuvor. "Wenn man sich strikt an den C ++ - Standard hält", erhalten sie andere Antworten als Sie. Ab einem frühen Entwurf für C ++ 11 können verschachtelte Klassen über eine Referenz / einen Zeiger auf alle Mitglieder des übergeordneten Elements zugreifen . Es besteht keine Verpflichtung, friendoder explizit zu deklarieren public. Wen kümmert es, wenn IBM in der Vergangenheit an einem toten Link falsch / veraltet war? Diese Antwort war bereits 3 Jahre vor ihrer Veröffentlichung veraltet.
underscore_d
1

Zunächst versuchen Sie, auf nicht statische Elemente varaußerhalb der Klasse zuzugreifen, die in C ++ nicht zulässig sind.

Marks Antwort ist richtig.

Alles, was Teil von Outer ist, sollte Zugang zu allen öffentlichen oder privaten Mitgliedern von Outer haben.

Sie können also zwei Dinge tun, entweder varals deklarieren staticoder eine Referenz einer Instanz der äußeren Klasse verwenden, um auf 'var' zuzugreifen (weil es sich um eine Friend-Klasse oder -Funktion handelt auch eine Referenz benötigt, um auf private Daten zuzugreifen).

Statische Var

Wechseln varzu staticWenn Sie nicht varmit den Instanzen der Klasse verknüpft werden möchten .

#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();

}

Ausgangsvariable: 1

Nicht statische var

Die Referenz eines Objekts muss auf nicht statische Elementvariablen zugreifen.

#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);

}

Ausgangsvariable: 1

Bearbeiten - Externe Links sind Links zu meinem Blog.

Adarsh ​​Kumar
quelle