为什么拥有私有基类的声明会使类型名称无法访问?

Joh*_*tes 10 c++ injected-class-name

令我感到惊讶的是,在下面的示例中,声明Middle的基类private使该名称在后续派生中不可用作为类型.

class Base {
public:
  Base(Base const& b) : i(b.i) {}

  int i;
};

class Middle : private Base {            //<<<<<<<<<<<
public:
  Middle(Base const* p) : Base(*p) {}
};

class Upper : public Middle {
public:
  Upper(Base const* p) : Middle(p) {}    //<<<<<<<<<<<
};
Run Code Online (Sandbox Code Playgroud)

用g ++编译(Debian 6.3.0-18 + deb9u1)6.3.0 20170516 ......

g++ -std=c++11 privateBase.cpp
Run Code Online (Sandbox Code Playgroud)

我得到以下诊断:

privateBase.cpp:15:9: error: ‘class Base Base::Base’ is inaccessible within this context
   Upper(Base const* p) : Middle(p) {}
         ^~~~
privateBase.cpp:1:12: note: declared here
 class Base {
            ^
Run Code Online (Sandbox Code Playgroud)

很明显,Base被用作Middle的基类,它的名字可以作为一种类型使用.我可以理解,当Base用于表示应该是私有的基类存储时.但是,拥有私有基类的声明使得类型名称无法访问似乎至少是意外的.

T.C*_*.C. 12

这是有意的; 看看核心问题175,它甚至在[class.access.spec] p5中添加了一个说明这个的例子:

[  注意:在派生类中,基类名称的查找将在声明它的作用域中找到inject-class-name而不是基类的名称.inject-name的名称可能比声明它的作用域中的基类名称更不易访问.-  尾注  ] [  示例:

class A { };
class B : private A { };
class C : public B {
  A* p;             // error: injected-class-name A is inaccessible
  ::A* q;           // OK
};
Run Code Online (Sandbox Code Playgroud)

-  结束例子  ]


这不属于类名注入之间的相互作用(对于基本原理,请参阅为什么有注入的类名?)以及C++访问控制在名称查找之后应用的事实,而不是之前的事实.

  • @RobertHarvey - [cppreference 解释](https://en.cppreference.com/w/cpp/language/injected-class-name) 是否足够:“在类作用域中,当前类的名称被视为 _as if它是一个公共成员名称_;这称为注入类名称。名称的声明点紧跟在类定义的左大括号之后。_与其他成员一样,注入类名称是继承的。_ 在存在的情况下对于私有或受保护的继承,间接基类的注入类名可能最终在派生类中无法访问。” (添加斜体。) (3认同)
  • 你忘了解释原因. (2认同)