为什么我们实际上在C ++中需要私有或受保护的inheritance?

在C ++中,我想不出一个我想从基类inheritanceprivate / protected的情况:

class Base; class Derived1 : private Base; class Derived2 : protected Base; 

它真的有用吗?

当你想访问基类的一些成员,但没有将它们暴露在类接口中时,这是非常有用的。 私有inheritance也可以被看作是某种组合: C ++ faq-lite给出了下面的例子来说明这个语句

 class Engine { public: Engine(int numCylinders); void start(); // Starts this Engine }; class Car { public: Car() : e_(8) { } // Initializes this Car with 8 cylinders void start() { e_.start(); } // Start this Car by starting its Engine private: Engine e_; // Car has-a Engine }; 

为了获得相同的语义,你也可以写汽车类如下:

 class Car : private Engine { // Car has-a Engine public: Car() : Engine(8) { } // Initializes this Car with 8 cylinders using Engine::start; // Start this Car by starting its Engine }; 

但是,这种做法有几个缺点:

  • 你的意图不太清楚
  • 它可能导致滥用多重inheritance
  • 它打破了引擎类的封装,因为你可以访问其受保护的成员
  • 你可以重写引擎虚拟方法,如果你的目标是一个简单的组合,这是你不想要的东西

私人在很多情况下都是有用的。 其中只有一个是政策:

部分类模板专业化是这个devise问题的答案吗? 。

另一个有用的场合是禁止复制和分配:

 struct noncopyable { private: noncopyable(noncopyable const&); noncopyable & operator=(noncopyable const&); }; class my_noncopyable_type : noncopyable { // ... }; 

因为我们不希望用户有一个types为noncopyable*的指针给我们的对象,所以我们私下导出。 这不仅仅是不可复制的,而且还有很多其他的类(政策是最常见的)。

公共inheritance模型IS-A。
非公有inheritance模型IS-IMPLEMENTED-IN-TERMS-OF。
遏制模型HAS-A相当于IS-IMPLEMENTED-IN-TERMS-OF。

萨特在这个话题上 。 他解释了什么时候你会select非公有inheritance来控制实现细节。

私有inheritance主要用于错误的原因。 人们把它用于IS-IMPLEMENT-IN-TERMS-OF,正如前面的答案所指出的那样,但根据我的经验,保留副本而不是inheritance课程总是比较干净的。 另一个较早的答案是关于CBigArray的答案,它提供了这种反模式的一个完美例子。

我意识到可能会有这样的情况:由于过度热心地使用“受保护的”,有-A不能工作,但是最好修复破碎的课程而不是打破新的课程。

例如,当你想重用实现,而不是一个类的接口,并重写它的虚函数。

我已经在一个点或其他地方使用了私有和受保护的inheritance。

当你想要某些东西具有基类的行为时,私有inheritance是有用的,然后能够覆盖这个function,但是你不希望整个世界知道它并使用它。 您仍然可以通过让函数返回该接口来使用私有派生类的接口。 当你可以注册自己的东西来监听callback,因为它们可以使用专用接口注册。

当你有一个基类从另一个类派生有用的function,但你只希望它的派生类能够使用它时,受保护的inheritance是特别有用的。

我曾经将这些数据结构实现为类:

  • 链接列表
  • 通用数组(抽象)
  • 简单数组(inheritance自generics数组)
  • 大数组(从generics数组inheritance而来)

大数组的接口将使它看起来像一个数组,然而,它实际上是一个固定大小的简单数组的链表。 所以我这样宣布:

 template <typename T> class CBigArray : public IArray, private CLnkList { // ...