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

时间:2018-12-27 18:44:32

标签: 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) {}    //<<<<<<<<<<<
};

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

g++ -std=c++11 privateBase.cpp

我得到以下诊断信息:

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 {
            ^

很明显,在将Base用作Middle的基类的时候,其名称可以用作类型。我可以理解,当使用Base表示应为私有的基类存储时。但是,至少有一个私有基类的声明会导致类型名称无法访问,这至少是意外的。

1 个答案:

答案 0 :(得分:12)

这是有意的;参见core issue 175,甚至在[class.access.spec] p5中添加了一个示例来说明这一点:

  

[注意:”在派生类中,将查找基类名称   注入的类名,而不是基类的名称   声明的范围。注入的类名可能更少   可以访问的范围比基类在其作用域中的名称   被宣布。 — 尾注] [示例:

class A { };
class B : private A { };
class C : public B {
  A* p;             // error: injected-class-name A is inaccessible
  ::A* q;           // OK
};
     

最终示例]


这不属于类名注入(有关原理,请参见Why is there an injected class name?)与C ++访问控制在名称查找之后而不是之前应用的事实之间的相互作用。