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::Basefrom的相同方法/属性?base::Base::Nestedinherited::Baseinherited::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.2) 的受保护成员时,将应用第 11 节中所述之外的附加访问检查 如前所述,授予对受保护成员的访问权限是因为引用发生在某个类 C 的朋友或成员中。如果访问要形成指向成员的指针 (5.3.1),则嵌套名称说明符应表示 C 或从 C 派生的类。所有其他访问都涉及 (可能是隐式的)对象表达式(5.2.5)。在这种情况下,对象表达式的类应为 C 或从 C 派生的类。

这并不容易解释。值得庆幸的是,该标准提供了许多示例来说明含义,其中一个似乎正是您的情况(除非我误解了您的代码中的某些内容,这很有可能):

(注意,为了简单起见,我删除了示例中不相关的部分,并重命名了一些元素。)

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是通过pb指向基类的指针找到的,因此命名类B. 但访问发生自mem(),它是 的成员DB与 不同D,也不是从它派生的(虽然D是从 派生的B),所以不允许访问。

但在

i = 3

该成员是通过 找到的this,因此命名类是D并且允许访问。

于 2012-10-13T14:55:12.477 回答