【问题标题】:Access to protected constructor of base class访问基类的受保护构造函数
【发布时间】:2014-08-29 10:46:41
【问题描述】:

派生类可以在其 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),则 nested-name-specifier 应表示 C 或 派生自C 的类。所有其他访问都涉及(可能是隐式的)对象表达式(5.2.5)。在这种情况下, 对象表达式的类应为C 或从C 派生的类。 [ 例子: ...

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

【问题讨论】:

  • 相关/重复:stackoverflow.com/q/2393325
  • 有趣的是,构造函数应该没有名称 [class.ctor],访问控制 不应该应用于它们;)(以及名称查找)
  • @dyp,我认为 OP 理解这种行为。他正在标准中寻找能够清楚解释这种行为的证据。您发布的链接没有任何指向标准中任何相关位置的答案,至少我没有看到任何答案。
  • @RSahu 我知道,但这并不能减少相关性/减少重复。 this 问题的答案也适用于其他问题。我没有将其作为重复项关闭,是吗?

标签: c++ oop language-lawyer


【解决方案1】:

protected 访问权限仅适用于您自己当前对象类型的父成员。您无法公开访问父类型的 other 对象的受保护成员。在您的示例中,您只能作为Derived 的一部分访问默认基本构造函数,而不是当它是b 的独立对象时。

让我们分解一下您从标准 (11.4/1) 中发布的报价。我们假设标准中的 C 对应于您的 Derived 类:

除前面第 11 条所述之外的附加访问检查 在非静态数据成员或非静态成员函数时应用 是其命名类 (11.2) 的受保护成员。

因此,基类构造函数在这里实际上是其命名类 (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())。现在我们检查一下:BaseC 还是 C 的子代?不是,所以代码不合法​​。

【讨论】:

  • 我明白了,但是标准中的哪个地方规定了这一点?
  • @Brian:您应该将该评论移至该问题。否则问题是重复的。
  • @Cheersandhth.-Alf 问题询问“标准对此有何评论”,但我还是对其进行了编辑以重申。
【解决方案2】:

C++11 §11.2/5:


当在类 N if

中命名时,成员 m 可在点 R 访问
  • m 作为N 的成员是公开的,或者

  • m 作为N 的成员是私有的,R 出现在N 类的成员或朋友中,或者

  • m 作为N 的成员受到保护,R 出现在N 类的成员或朋友中, 或在类P 的成员或朋友中派生 来自N,其中m 作为P 的成员是公共的、私有的或受保护的,或者

  • 存在N 的基类B,可通过R 访问, m 在类B 中命名时可在R 访问。

对于你的构造函数调用

Base b2;

上述第 3rd 点适用。 mBase 构造函数。 N,命名类,是Basem 作为Base 的成员是受保护的,并且声明发生在从Base 派生的类Derived 的成员中,但作为Derived 成员的Base 构造函数并非如此公共、私有或受保护:它根本不是Derived 的成员,构造函数不是隐式继承的。

我认为“是公共的、私有的或受保护的”语言很尴尬;我只能推测这是这一段的一些演变的结果。

我还没有找到解释受保护的Base 构造函数在Derived 的成员初始化器列表中是如何访问的,但后来我才开始研究这个问题。


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

【讨论】:

  • 啊,”有点意思,对不起。
  • @dyp:感谢您的编辑,我认为引用非常忠实于原文非常重要。不相关:寻找其他地方,谷歌搜索,我认为 IBM's documentation 可能很难被称为权威,因为它包含 void main 的示例:(
  • “这很可能是一个缺陷。” 如果您想提请委员会注意,请注意构造函数应该没有名称 [class.ctor]/ 1.因此,我想很多关于名称的可访问性 的文本不应该适用于他们。 (但话说回来,构造函数可以通过名称查找 [class.qual]/2 找到,所以这可能是另一个不相关的缺陷。)
猜你喜欢
  • 2011-05-02
  • 2015-08-12
  • 2018-07-16
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 2012-12-07
相关资源
最近更新 更多