2

次のコードを検討してください。

namespace base {
class Base {
    protected:
        class Nested {
            protected:
                Base* base;

            public:
                Nested(Base* _base) : base( _base ){}

                virtual void test() {
                    base->foo();
                    /*
                     * hmm.. we can use protected methods
                     */
                    base->bar();
                }
        };

    protected:
        Nested* nested;

        void bar(){}

    public:
        void foo(){}

        virtual void test() {
            nested = new Nested(this);
            nested->test();
        }
};
};

namespace inherited {
class Base : public base::Base {
    public:
        Base()
            : base::Base() {}

    protected:
        class Nested : public base::Base::Nested {
            public:
                Nested( inherited::Base* base )
                    : base::Base::Nested( base ) {}

            public:
                virtual void test() {
                    base->foo();
                    /*
                     * hmm.. and now they are not accessible
                     */
                    // base->bar();
                }
        };

    public:
        virtual void test() {
            foo();
            bar();

            nested = new Nested(this);
            nested->test();
        }
};
};

私の質問は、 from の保護されたメソッド/プロパティにアクセスできるのに、 base::Basefrombase::Base::Nestedの同じメソッド/プロパティにアクセスできないのinherited::Baseはなぜinherited::Base::Nestedですか?

私が推測できる唯一のことはbase::Base、それが一種のグローバルスコープbase::Base::Nestedあるため、アクセス可能であることです。inherited::Baseは一種のグローバル スコープinherited::Base::Nestedあり、 の保護されたメンバーにbase::Baseはアクセスできません。ただし、パブリック継承は可視性の範囲を変更するべきではなく、アクセスできない理由は不明です。

4

2 に答える 2

2

問題は、アクセス権ではなく、格納されたポインターのタイプにあるようです。このことを考慮:

class B {
protected:
  void bar();
};

class D : public B {
public:
  void call() {
    this->bar(); // works
    static_cast<B*>(this)->bar(); // does not work
  }
};

barベースに格納されているポインターを介して呼び出しを試みた場合も同様です。

ベースをダウンキャストすることでこの問題を回避できますが、私は強く反対します。

于 2012-10-13T13:47:52.563 に答える
1

§11.4/1 には、保護されたメンバーへのアクセスについて次のように書かれています (関連部分の強調は私によるものです)。

非静的データ メンバーまたは非静的メンバー関数がその命名クラスの保護されたメンバーである場合、条項 11 で前述したものを超える追加のアクセス チェックが適用されます (11.2)。前述のように、保護されたメンバーへのアクセスは、アクセスがメンバーへのポインターを形成する場合 (5.3.1)、nested-name-specifier は C または C から派生したクラスを示す必要があります。他のすべてのアクセスには (おそらく暗黙の)オブジェクト式(5.2.5)。この場合、オブジェクト式のクラスは C または C から派生したクラスでなければなりません。

これを解釈するのは容易ではありません。ありがたいことに、標準は意味を説明するために多くの例を示しており、そのうちの1つはまさにあなたのケースのようです(コードで何かを誤解していない限り、それはかなり可能です):

(簡単にするために、例の無関係な部分を削除し、いくつかの要素の名前を変更したことに注意してください。)

class B {
  protected:
  int i;
  static int j;
};

class D : public B {
  void mem(B*);
};


void D::mem(B* pb) {
  pb->i = 1;                // ill-formed
  i = 3;                    // OK (access through this)

  /* The following cases are not directly relevant: */
  B::i = 4;                 // OK (access through this, qualification ignored)
  int B::* pmi_B = &B::i;   // ill-formed
  int B::* pmi_B2 = &D::i;  // OK
  j = 5;                    // OK (because j refers to a static member)
  B::j = 6;                 // OK (because B::j refers to a static member)
}

言い換えれば、

pb->i = 1;

メンバーは、基本クラスへのポインタであるiを通じて検出されるため、ネーミング クラスはです。しかし、アクセスは のメンバーであるから発生します。は と同一ではなく、そこから派生したものでもありません ( から派生していますが)。そのため、アクセスは許可されません。pbBmem()DBDDB

しかし、

i = 3

メンバーは を通じて検出されるthisため、命名クラスは でDあり、アクセスが許可されます。

于 2012-10-13T14:55:12.477 に答える