内部クラスはプライベート変数にアクセスできますか?


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

これは、クラスOuter :: Inner 'でコンパイルすると、「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を参照してください。ただし、
グレッグロジャース

1
その価値については、GCCはそこで提案された解決策に従いますが、他のコンパイラもおそらくそうします。
グレッグロジャース

24
C + 11標準は、上記の説明に準拠しています。
マーティンヨーク

1
Javaでは、非静的内部クラスには、内部クラスが最初にアクセスされたときに、その外部クラスのインスタンスへの参照(ポインタ)が暗黙的に与えられます。これを言い換えると、jvmは@LokiAstariが彼の回答で示したものと同様のコードを暗黙的に記述しています。これは、Effective Java 2nd Ed「Item 22:Favor static member classes over nonstatic」からの抜粋です。
デビッドリー

3
@Loki Astari:「親子関係を手動で作成する必要があります」という最後の文を読み、それに続くコードフラグメントを、それを正しく行う方法の例として解釈しました
ブレント

32

内部クラスは外部クラスのすべてのメンバーにアクセスできますが、Javaの奇妙な点とは異なり、親クラスインスタンスへの暗黙的な参照はありません。したがって、外部クラスへの参照を内部クラスに渡すと、外部クラスインスタンスのすべてを参照できます。


7
これは、c ++ 11から当てはまります
thrantir 2014

6

Outerの一部であるものはすべて、パブリックまたはプライベートのすべてのOuterのメンバーにアクセスできる必要があります。

編集:あなたのコンパイラは正しいです、varはInnerのメンバーではありません。しかし、Outerのインスタンスへの参照またはポインタがあれば、それにアクセスできます。


2

varは内部クラスのメンバーではありません。

varにアクセスするには、外部クラスインスタンスへのポインタまたは参照を使用する必要があります。たとえば、pOuter-> varは、内部クラスが外部のフレンドである場合、またはC ++標準に厳密に従っている場合、varがパブリックの場合に機能します。

一部のコンパイラは内部クラスを外部のフレンドとして扱いますが、そうでないコンパイラもあります。IBMコンパイラについては、次のドキュメントを参照してください。

「ネストされたクラスは別のクラスのスコープ内で宣言されます。ネストされたクラスの名前は、それを囲むクラスに対してローカルです。明示的なポインター、参照、またはオブジェクト名を使用しない限り、ネストされたクラスの宣言は、型名、静的メンバー、および包含クラスとグローバル変数からの列挙子。

ネストされたクラスのメンバー関数は通常のアクセスルールに従い、それらを含むクラスのメンバーへの特別なアクセス権限はありません。外側のクラスのメンバー関数は、ネストされたクラスのメンバーに特別なアクセス権を持ちません。」


4
違う。他の回答を見る-3年前。「C ++標準に厳密に従っている場合」は、あなたの回答とは異なる回答になります。C ++ 11の初期のドラフトでは、ネストされたクラスは、参照/ポインタを介して親のすべてのメンバーにアクセスできます。friendまたはを明示的に宣言する必要はありませんpublic。IBMが過去にデッドリンクで誤解/古くなっていたかどうかは誰が気にかけますか?この回答は、投稿される3年前にすでに古くなっています。
underscore_d 2015

1

まずvar、C ++では許可されていない、クラス外の非静的メンバーにアクセスしようとしています。

マークの答えは正しいです。

Outerの一部であるものはすべて、パブリックまたはプライベートのすべてのOuterのメンバーにアクセスできる必要があります。

したがって、外部クラスのインスタンスの宣言varとして宣言するstaticか、その参照を使用して「var」にアクセスするという2つのことを実行できます(フレンドクラスまたは関数もプライベートデータにアクセスするための参照が必要なため)。

静的変数

クラスのインスタンスに関連付けられないようにするには、に変更varstaticます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

編集-外部リンクは私のブログへのリンクです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.