请考虑以下代码:
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
访问base::Base::Nested
的受保护方法/属性,但无法访问inherited::Base
中inherited::Base::Nested
的相同方法/属性?< / p>
我唯一能想到的是base::Base
是base::Base::Nested
的一种全局范围,因此它们是可访问的。 inherited::Base
是inherited::Base::Nested
的一种全局范围,base::Base
的受保护成员无法访问。但是,公共继承不应该改变可见性的范围,并且我不清楚访问无能的原因。
答案 0 :(得分: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
呼叫时,情况类似
存储在基础中的指针。
你可以通过降级基础解决这个问题,但我强烈反对。
答案 1 :(得分:1)
§11.4/ 1对访问受保护成员有所说明(由我强调相关部分):
当非静态数据成员或非静态成员函数是其命名类的受保护成员时,将应用超出第11章中所述之外的其他访问检查(11.2)如前所述,访问a保护成员被授予,因为引用发生在朋友或某个类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
是B
的成员。 D
与D
不同,也不是从B
派生的(尽管i = 3
来自this
),因此不允许访问。
但是在
D
通过{{1}}找到该成员,因此命名类为{{1}}并允许访问。