【问题标题】:Inheritance of nested class and visibility scope嵌套类和可见范围的继承
【发布时间】:2012-10-13 13:01:39
【问题描述】:

考虑以下代码:

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

我的问题是为什么我们可以从base::Base::Nested 访问base::Base 的受保护方法/属性,但不能从inherited::Base::Nested 访问inherited::Base 的相同方法/属性?

我唯一能想到的是base::Basebase::Base::Nested 的一种全局范围,因此它们是可访问的。 inherited::Baseinherited::Base::Nested 的一种全局范围base::Base 的受保护成员不可访问。但是,公共继承不应该改变可见性范围,我不清楚无法访问的原因。

【问题讨论】:

  • 你的思维方式很奇怪。继承::基础?无论如何,为了这个示例的目的,去掉 80% 的代码,制作 Base、BaseNested、Derived 和 DerivedNested 类,并去掉所有不能证明您的问题的函数。
  • 请尽量避免代码中不必要的杂乱(命名空间、太多成员)并使其可编译(没有奇怪的未定义宏,没有丢失的包含)。否则是个好问题。
  • 有什么理由认为这不是stackoverflow.com/questions/4672438/…的副本?

标签: c++ inheritance nested-class


【解决方案1】:

问题似乎是存储指针的类型而不是访问权限。考虑一下:

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

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

当您尝试通过 存储在基址中的指针。

你可以通过降低基数来解决这个问题,但我强烈反对。

【讨论】:

  • 终于明白了。我正在尝试从inherited::Base::Nested::test() 访问受保护的方法base::Base::bar(),因为base::Base::Nested::base(和inherited::Base::Nested::base)是base::Base 类型的指针,而不是inherited::Base 类型的指针。现在我很清楚了。
  • @ilardm 相关标准报价请参考jogojapan的回答。这种行为看似不直观,但却是必要的,因此不能轻易规避访问限制。
【解决方案2】:

§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(),它是D 的成员。 BD不完全相同,也不是从D派生出来的(虽然D是从B派生的),所以不允许访问。

但是在

i = 3

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

【讨论】:

    猜你喜欢
    • 2012-11-30
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多