C++:可以从 Class 及其受保护的成员类型继承吗?

C++: Is It OK to Inherit from a Class and Its Protected Member Type?

以下代码是否符合 C++ 标准?

struct B
{
protected:
    struct Type {};
};

struct D : B, B::Type
{};

int main()
{
    D d;
    return 0;
}

我在 Compiler Explorer 上试过了。 MSVC(VS 2017 RTW) 接受它。 gcc(7.3) 和 clang(6.0.0) 拒绝它。

如果 D 派生自 B,它可以访问其受保护的成员,所以这应该是正确的。问题是它在那个编译点是否已经已经 访问,或者它是否只有在类型完成后才能访问。

请注意,如果将两者反过来(将 B 放在逗号后面),它应该会失败。

该代码符合标准,自 C++11 开始,但不在 C++03 中。

C++11 到 C++17 在 [class.access] 部分的介绍中这样说,成员访问控制:

All access controls in clause [class.access] affect the ability to access a class member name from the declaration of a particular entity, including parts of the declaration preceding the name of the entity being declared and, if the entity is a class, the definitions of members of the class appearing outside the class's member-specification.

在那些相同的标准版本中,下面的示例与您的问题非常相似,但甚至有点棘手:

[Example:

  class A {
...
  protected:
      struct B { };
  };
...

  struct D: A::B, A { };

... The use of A::B as a base-specifier is well-formed because D is derived from A, so checking of base-specifiers must be deferred until the entire base-specifier-list has been seen. -end example]

但我看到了与您相同的结果:g++ 和 clang++ 都拒绝这些程序,无论我给出什么 -std= 参数。这是一对编译器错误。

C++03 有这个而不是我上面引用的第一段:

All access controls in clause [class.access] affect the ability to access a class member name from a particular scope. The access control for names used in the definition of a class member that appears outside of the member's class definition is done as if the entire member definition appeared in the scope of the member's class....

class 定义的 base-specifier 不在那个 class 的范围内,所以 C++03 不允许使用受保护或私有名称作为派生 class 的基 class 的名称,否则可以访问该名称。