Les classes internes peuvent-elles accéder aux variables privées?

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

Cette erreur se produit lorsque je compile avec la classe Outer :: Inner 'n'a aucun membre nommé `var'

Kal
la source

Réponses:

120

Une classe interne est un ami de la classe dans laquelle elle est définie.
Donc oui; un objet de type Outer::Innerpeut accéder à la variable membre vard'un objet de type Outer.

Contrairement à Java, il n'y a pas de corrélation entre un objet de type Outer::Inneret un objet de la classe parent. Vous devez créer la relation parent-enfant manuellement.

#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
la source
14
Techniquement, dans la norme C ++ actuelle, une classe imbriquée n'a PAS d'accès spécial à sa classe englobante. Voir sec 11.8.1 de la norme. CEPENDANT, voyez aussi ce défaut standard: open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45
Greg Rogers
1
Pour ce que cela vaut, GCC suit la résolution proposée qui y est donnée, d'autres compilateurs le font probablement aussi.
Greg Rogers
24
La norme C + 11 est désormais conforme à la description ci-dessus.
Martin York
1
En Java, la classe interne non statique reçoit implicitement une référence (pointeur) vers l'instance de sa classe externe lors du premier accès à la classe interne. Pour reformuler cela, jvm écrit implicitement pour vous un code similaire à ce que @LokiAstari nous a montré dans sa réponse. Voici un extrait de Effective Java 2nd Ed "Item 22: Favoriser les classes membres statiques par rapport aux nonstatic": "Si vous omettez ce modificateur (mot-clé statique lors de la déclaration de classe interne), chaque instance aura une référence étrangère à son instance englobante".
David Lee
3
@Loki Astari: J'ai lu la dernière phrase "Vous devez faire la relation parent-enfant manuellement" et interprété le fragment de code qui a suivi comme un exemple de la façon de le faire correctement !
Brent Baccala
32

Une classe interne a accès à tous les membres de la classe externe, mais elle n'a pas de référence implicite à une instance de classe parente (contrairement à certaines bizarreries avec Java). Donc, si vous transmettez une référence à la classe externe à la classe interne, elle peut référencer n'importe quoi dans l'instance de classe externe.

MSN
la source
7
cela est vrai de c ++ 11
thrantir
6

Tout ce qui fait partie d'Outer doit avoir accès à tous les membres d'Outer, publics ou privés.

Edit: votre compilateur est correct, var n'est pas membre d'Inner. Mais si vous avez une référence ou un pointeur vers une instance d'Outer, il pourrait y accéder.

Mark Ransom
la source
2

var n'est pas membre de la classe interne.

Pour accéder à var, un pointeur ou une référence à une instance de classe externe doit être utilisé. par exemple pOuter-> var fonctionnera si la classe interne est un ami de external, ou, var est public, si l'on suit strictement le standard C ++.

Certains compilateurs traitent les classes internes comme l'ami de l'extérieur, mais d'autres non. Voir ce document pour le compilateur IBM :

"Une classe imbriquée est déclarée dans la portée d'une autre classe. Le nom d'une classe imbriquée est local par rapport à sa classe englobante. À moins que vous n'utilisiez des pointeurs, des références ou des noms d'objet explicites, les déclarations d'une classe imbriquée ne peuvent utiliser que des constructions visibles, y compris noms de type, membres statiques et énumérateurs de la classe englobante et des variables globales.

Les fonctions membres d'une classe imbriquée suivent les règles d'accès normales et n'ont pas de privilèges d'accès spéciaux aux membres de leurs classes englobantes. Les fonctions membres de la classe englobante n'ont pas d'accès spécial aux membres d'une classe imbriquée. "

xiaochuanQ
la source
4
Faux. Voir d'autres réponses - 3 ans plus tôt. "si l'on suit strictement le standard C ++", ils atteignent des réponses différentes des vôtres. À partir d'un premier brouillon pour C ++ 11, les classes imbriquées peuvent accéder à tous les membres du parent via une référence / un pointeur. Il n'y a aucune obligation de déclarer explicitement friendou public. Qui se soucie si IBM avait tort / dépassé, dans le passé, à un lien mort? Cette réponse était déjà obsolète 3 ans avant sa publication.
underscore_d
1

Tout d'abord, vous essayez d'accéder à un membre non statique en vardehors de la classe, ce qui n'est pas autorisé en C ++.

La réponse de Mark est correcte.

Tout ce qui fait partie d'Outer doit avoir accès à tous les membres d'Outer, publics ou privés.

Vous pouvez donc faire deux choses, soit déclarer en vartant que staticou utiliser une référence d'une instance de la classe externe pour accéder à 'var' (car une classe ou une fonction également besoin d'une référence pour accéder aux données privées).

Var statique

Remplacez varpar staticSi vous ne souhaitez varpas être associé aux instances de la classe.

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

}

Sortie- var: 1

Var non statique

La référence d'un objet doit accéder à toutes les variables membres non statiques.

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

}

Sortie- var: 1

Modifier - Les liens externes sont des liens vers mon blog.

Adarsh ​​Kumar
la source