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

时间:2008-12-17 12:29:43

标签: c++ inheritance private protected c++-faq

在C ++中,我想不出一个我想继承private / protected的案例 基类:

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

真的有用吗?

7 个答案:

答案 0 :(得分:44)

当您想要访问基类的某些成员但不在类接口中公开它们时,它非常有用。私有继承也可以被视为某种组合: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
}; 

然而,这种做法有几个缺点:

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

答案 1 :(得分:40)

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

Is partial class template specialization the answer to this design problem?

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

struct noncopyable {
    private:
    noncopyable(noncopyable const&);
    noncopyable & operator=(noncopyable const&);
};

class my_noncopyable_type : noncopyable {
    // ...
};

因为我们不希望用户的对象具有类型为noncopyable*的指针,所以我们私下派生。这不仅适用于不可复制的,也适用于许多其他此类类(策略是最常见的)。

答案 2 :(得分:15)

公共继承模型IS-A。
非公开继承模型IS-IMPLEMENTED-IN-TERMS-OF 收容模型HAS-A,相当于IS-IMPLEMENTED-IN-TERMS-OF。

Sutter on the topic。他解释了当您为实施细节选择非公开继承而非遏制时。

答案 3 :(得分:3)

例如,当您想重用实现时,而不是类的接口AND覆盖其虚函数。

答案 4 :(得分:3)

私有继承主要用于错误的原因。如前面的回答所示,人们将它用于IS-IMPLEMENTED-TERMS-OF,但根据我的经验,保留副本而不是继承课程总是更加干净。另一个早期的答案,关于CBigArray的答案,提供了这种反模式的完美例子。

我意识到有些情况下,由于过度热衷于使用“受保护”而导致a-a无法正常工作,但是修复破坏的类比破坏新类更好。

答案 5 :(得分:0)

我在某一点或其他地方都使用了私有和受保护的继承。

当您希望某些东西具有基类的行为,然后能够覆盖该功能,但您不希望整个世界意识到并使用它时,私有继承非常有用。您仍然可以通过让函数返回该接口来使用私有派生类的接口。当你可以注册自己来监听回调时,它也很有用,因为他们可以使用私有接口注册自己。

当您有一个从另一个类派生有用功能但只希望其派生类能够使用它的基类时,受保护的继承特别有用。

答案 6 :(得分:-1)

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

  • 链接列表
  • 通用数组(摘要)
  • 简单数组(继承自通用数组)
  • 大数组(继承自通用数组)

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

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