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