访问受保护的基类构造函数

时间:2014-07-08 15:47:37

标签: c++ oop language-lawyer

派生类可以在其 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的类。 [示例: ...

调用构造函数时是否涉及对象表达式?没有,有吗?那么标准中的哪个位置是受保护的基类构造函数的访问控制?

2 个答案:

答案 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())。现在我们进行检查:BaseC还是孩子的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 点适用。 mBase构造函数。命名类NBase。作为m成员的Base受到保护,声明发生在Derived派生的Base类成员中,但Base并非如此构造函数作为Derived的成员是public,private或protected:它不是Derived的成员,构造函数不是隐式继承的。

我认为“公共,私人或受保护”的语言非常尴尬;我只能猜测这是本段某些演变的结果。

我还没有找到关于Base中成员初始值设定项列表中如何正式访问受保护Derived构造函数的解释,但后来我才开始查看此问题。


更新:我在标准中找不到与初始化列表中的构造函数访问有关的任何语言,但我找不到任何关于它的缺陷报告。这很可能是一个缺陷。