12

令我惊讶的是,在以下示例中,将 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 用于表示应该是私有的基类存储时。但是,至少声明一个私有基类会使类型名称无法访问,这似乎是出乎意料的。

4

1 回答 1

15

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

[ <em>注意:在派生类中,基类名称的查找将找到注入的类名称,而不是声明它的范围内的基类名称。在声明它的范围内,注入的类名可能比基类的名称更难访问。— <em>结束注释] [ <em>示例:

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

— <em>结束示例]


这不属于类名注入(有关基本原理,请参阅Why is there an injection class name?)和在 C++ 中访问控制在名称查找之后而不是之前应用的事实之间的交互。

于 2018-12-27T18:58:51.067 回答