访问受保护的基类的构造函数
派生类可以在其ctor-initializer中调用受保护的基类构造函数,但仅针对其自己的基类子对象,并不在其他地方:
class Base {
protected:
Base() {}
};
class Derived : Base {
Base b;
public:
Derived(): Base(), // OK
b() { // error
Base b2; // error
}
};
标准对此有何评论? 这是[class.protected] / 1:
如果非静态数据成员或非静态成员函数是其命名类的受保护成员(11.2),则会应用除第11节中前面所述之外的其他访问权限检查(11.2)。如前所述,授予对受保护成员的访问权限,因为参考发生在朋友或某个C
类的成员中。 如果访问要形成一个指向成员(5.3.1)的指针,则嵌套名称说明符应表示C
或从C
派生的类。 所有其他访问涉及(可能是隐含的)对象表达式(5.2.5)。 在这种情况下,对象表达式的类应该是C
或从C
派生的类。 [例如:...
调用构造函数时是否存在一个对象表达式? 没有,是吗? 那么标准中的受保护基类构造函数的访问控制在哪里描述?
C ++ 11§11.2/ 5:
”
当在类N
命名时,成员m
可在点R访问
m
作为N
的成员是公共的,或者
m
作为N
的成员是私人的,R发生在N
类的成员或朋友中,或者
m
作为成员N
被保护,和R在A类成员或朋友发生N
,或在一个类的成员或朋友P
衍生自N
,其中m
作为一个构件P
是公共的,私人的,或受保护的,要么
存在可在R处访问的N
的基类B
,并且当在类B
命名时, m
在R处可访问。
用于构造函数的调用
Base b2;
以上第三点适用。 m
是Base
构造函数。 N
是命名类,是Base
。 m
作为Base
成员受到保护,并且声明发生在Derived
自Base
Derived
类的成员中,但不是Base
构造函数作为Derived
的成员是public,private或protected:它根本不是Derived
,构造函数不隐式地继承。
我认为这种语言“公开,私人或保护”是非常尴尬的; 我只能推测这是本段演变的结果。
我还没有找到解释在Derived
的成员初始化程序列表中如何正式访问受保护的Base
构造函数,但是我刚开始考虑这个问题。
更新:我未能在标准中找到与初始化程序列表中的构造函数有关的任何语言,并且我无法找到任何关于它的缺陷报告。 这很可能是一个缺陷。
protected
访问仅适用于您当前对象类型的父成员。 您不能公开访问父类型的其他对象的受保护成员。 在您的例子中,你只可以访问默认的基本构造器的一部分Derived
,而不是当它是一个独立的对象b
。
我们来分解一下你从标准中发布的报价(11.4 / 1)。 我们假定标准中的C
对应于你的Derived
类:
当非静态数据成员或非静态成员函数是其命名类(11.2)的受保护成员时,将应用超出第11章中描述的访问权限以外的其他访问权限检查。
所以基类构造函数实际上是它的命名类( B
)的non-static member function
,所以这个子句适用于目前为止。
如前所述,访问受保护的成员是被授予的,因为该引用发生在朋友或某个类C的成员中
C
成员(构造函数),所以我们在这里仍然很好。
如果访问形成一个指向成员的指针(5.3.1),则嵌套名称说明符应表示C或从C派生的类。
这不是指向成员的指针,所以这不适用。
所有其他访问涉及(可能是隐含的)对象表达式(5.2.5)。
然后标准声明所有其他可能的访问都必须包含一个对象表达式。
在这种情况下,对象表达式的类应该是C或从C派生的类。
最后,标准规定表达式的类必须是C
或另一个派生类。 在这种情况下,你的表达式Base()
实际上是一个C
,调用父构造函数(考虑它this->Base()
。表达式b
显然是Base
类型的(这是成员b
的显式声明类型,认为关于this->b->Base()
现在我们做的检查:是Base
一C
或孩子C
它不是,所以代码是不合法的?