简体   繁体   English

为什么我们实际上需要 C++ 中的 Private 或 Protected 继承?

[英]Why do we actually need Private or Protected inheritance in C++?

In C++, I can't think of a case in which I would like to inherit private/protected from a base class:在 C++ 中,我想不出我想从基类继承私有/受保护的情况:

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

Is it really useful?真的有用吗?

It is useful when you want to have access to some members of the base class, but without exposing them in your class interface. 当您想要访问基类的某些成员但不在类接口中公开它们时,它非常有用。 Private inheritance can also be seen as some kind of composition: the C++ faq-lite gives the following example to illustrate this statement 私有继承也可以看作是某种组合: 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
};

To obtain the same semantic, you could also write the car Class as follow: 要获得相同的语义,您还可以编写汽车类如下:

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
}; 

However, this way of doing has several disadvantages: 但是,这种做法有几个缺点:

  • your intent is much less clear 你的意图不太清楚
  • it can lead to abusive multiple inheritance 它可能导致滥用多重继承
  • it breaks the encapsulation of the Engine class since you can access its protected members 它打破了Engine类的封装,因为您可以访问其受保护的成员
  • you're allowed to override Engine virtual methods, which is something you don't want if your aim is a simple composition 你被允许覆盖引擎虚拟方法,如果你的目标是一个简单的组合,这是你不想要的

Private can be useful in quite a few circumstances. 私人在很多情况下都很有用。 Just one of them are policies: 其中只有一个是政策:

Is partial class template specialization the answer to this design problem? 部分类模板专业化是这个设计问题的答案吗? .

Another occasion where it is useful is to forbid copying and assigning: 另一个有用的场合是禁止复制和分配:

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

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

Because we don't want that the user has a pointer of type noncopyable* to our object, we derive privately. 因为我们不希望用户的对象具有类型为noncopyable*的指针,所以我们私下派生。 That counts not only for noncopyable, but many other such classes too (policies being the most common). 这不仅适用于不可复制的,也适用于许多其他此类类(策略是最常见的)。

Public inheritance models IS-A. 公共继承模型IS-A。
Non-public inheritance models IS-IMPLEMENTED-IN-TERMS-OF. 非公开继承模型IS-IMPLEMENTED-IN-TERMS-OF。
Containment models HAS-A, which is equivalent to IS-IMPLEMENTED-IN-TERMS-OF. 收容模型HAS-A,相当于IS-IMPLEMENTED-IN-TERMS-OF。

Sutter on the topic . 萨特谈论这个话题 He explains when you'd choose non-public inheritance over containment for implementation details. 他解释了当你为实现细节选择非公开继承而非遏制时。

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

Private inheritance is mostly used for wrong reason. 私有继承主要用于错误的原因。 People use it to IS-IMPLEMENTED-IN-TERMS-OF, as indicated in an earlier answer, but in my experience it's always more clean to keep a copy rather than inherit from class. 如前面的回答所示,人们将它用于IS-IMPLEMENTED-TERMS-OF,但根据我的经验,保留副本而不是继承课程总是更加干净。 Another earlier answer, the one about CBigArray, provides a perfect example of this anti-pattern. 另一个早期的答案,关于CBigArray的答案,提供了这种反模式的完美例子。

I realize that there may be cases when has-a does not work due to over-zealous use of "protected", but it's better to fix the broken class than to break a new class. 我意识到有些情况下has-a由于过度热衷于使用“受保护”而无效,但是修复破坏的类比破坏新类更好。

I've used both private and protected inheritence at one point or other. 我曾经在某一点或其他地方使用过私人和受保护的遗产。

Private inheritence is useful when you want something to have the behaviour of the base class, and then be able to override that functionality, but you don't want the whole world to be aware of it and use it. 当您希望某些东西具有基类的行为,然后能够覆盖该功能时,私有继承是有用的,但您不希望整个世界都知道它并使用它。 You can still use the interface of a privately derived class by having a function return that interface. 您仍然可以通过让函数返回该接口来使用私有派生类的接口。 It's also useful when you can have things register themselves to listen for callbacks as they can register themselves using the private interface. 当你可以注册自己来监听回调时它也很有用,因为它们可以使用私有接口注册自己。

Protected inheritence is especially useful when you have a base class that derives useful functionality from another class but you only want its derived classes to be able to use it. 当您拥有从另一个类派生有用功能但只希望其派生类能够使用它的基类时,受保护的继承特别有用。

Private inheritance is most likely to be a legitimate design strategy when you're dealing with two classes not related by is-a where one either needs access to the protected members of another or needs to redefine one or more of its virtual functions.当您处理与 is-a 不相关的两个类时,私有继承很可能是一种合法的设计策略,其中一个需要访问另一个的受保护成员或需要重新定义其一个或多个虚函数。

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

I once implemented these data structures as classes: 我曾经将这些数据结构实现为类:

  • Linked list 链接列表
  • Generic array (abstract) 通用数组(摘要)
  • Simple array (inherits from generic array) 简单数组(继承自泛型数组)
  • Big array (inherits from generic array) 大数组(继承自泛型数组)

The big array's interface would make it look like an array, however, it was actually a linked list of fixed-size simple arrays. 大数组的接口会使它看起来像一个数组,但它实际上是一个固定大小的简单数组的链表。 So I declared it like this: 所以我宣布这样:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM