67

在 C++ 中,我想不出我想从基类继承私有/受保护的情况:

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

真的有用吗?

4

8 回答 8

54

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

为了获得相同的语义,您还可以编写 car 类,如下所示:

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 类的封装,因为您可以访问其受保护的成员
  • 您可以覆盖 Engine 虚拟方法,如果您的目标是简单的组合,这是您不想要的
于 2008-12-17T12:40:08.810 回答
40

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

部分类模板专业化是这个设计问题的答案吗?.

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

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

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

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

于 2008-12-17T12:36:30.067 回答
16

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

萨特的话题。他解释了当你选择非公共继承而不是包含实现细节时。

于 2008-12-17T14:21:14.300 回答
3

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

于 2008-12-17T16:01:34.380 回答
3

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

我意识到,由于过度使用“受保护”,has-a 可能会不起作用,但修复损坏的类比打破一个新的类更好。

于 2008-12-18T14:50:13.633 回答
1

我曾在某一时刻同时使用私有继承和受保护继承。

当您希望某些东西具有基类的行为,然后能够覆盖该功能,但您不希望全世界都知道并使用它时,私有继承很有用。您仍然可以通过让函数返回该接口来使用私有派生类的接口。当您可以让事物注册自己以侦听回调时,它也很有用,因为它们可以使用私有接口注册自己。

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

于 2008-12-17T16:03:51.630 回答
0

当您处理与 is-a 不相关的两个类时,私有继承很可能是一种合法的设计策略,其中一个类要么需要访问另一个的受保护成员,要么需要重新定义其一个或多个虚函数。

来自 Scott Meyers Effective C++ 3rd Edition page in 191。

于 2022-01-22T03:15:29.983 回答
-1

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

  • 链表
  • 泛型数组(抽象)
  • 简单数组(从泛型数组继承)
  • 大数组(从泛型数组继承)

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

template <typename T>
class CBigArray : public IArray, private CLnkList {
    // ...
于 2008-12-17T16:08:19.217 回答