为什么在C++;? 在C++中,我无法想到一个我想继承私有/保护的情况。 基类: class Base; class Derived1 : private Base; class Derived2 : protected Base;

为什么在C++;? 在C++中,我无法想到一个我想继承私有/保护的情况。 基类: class Base; class Derived1 : private Base; class Derived2 : protected Base;,c++,inheritance,private,protected,c++-faq,C++,Inheritance,Private,Protected,C++ Faq,它真的有用吗?私有在很多情况下都有用。其中只有一项是政策: 另一个有用的场合是禁止复制和分配: struct noncopyable { private: noncopyable(noncopyable const&); noncopyable & operator=(noncopyable const&); }; class my_noncopyable_type : noncopyable { // ... }; 因为我们不希望用

它真的有用吗?

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

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

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

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

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

当您希望访问基类的某些成员,但不在类接口中公开它们时,它非常有用。私有继承也可以被看作是某种组合:下面给出了一个示例来说明这条语句

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
}; 
然而,这种做法有几个缺点:

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

公共继承模型是-A.
非公共继承模型是根据实现的。
安全壳模型具有-A,相当于is-IMPLEMENTED-IN-OF


。他解释了何时选择非公共继承而不是包含作为实现细节。

例如,当您希望重用实现而不是类的接口并重写其虚拟函数时。

我曾在某一点上使用过私有继承和受保护继承

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


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

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

  • 链表
  • 泛型数组(摘要)
  • 简单数组(从泛型数组继承)
  • 大数组(从通用数组继承)
大数组的接口将使它看起来像一个数组,然而,它实际上是一个固定大小的简单数组的链接列表。所以我这样宣布:

template <typename T>
class CBigArray : public IArray, private CLnkList {
    // ...
模板
CBI类:公共图书馆、私人图书馆{
// ...

私有继承的使用大多是出于错误的原因。正如前面的答案所示,人们使用私有继承来实现,但根据我的经验,保留副本总是比从类继承更干净。另一个早期的答案,关于CBigArray的答案,提供了这种反模式的完美示例


我意识到可能有一些情况下,has-a由于过度使用“protected”而无法工作,但修复坏掉的类比破坏新类要好。

在我看来,如果是“has-a”不应该有任何继承,但应该有一个组合。我认为这是一个滥用继承的坏例子,因为它会让用户感到困惑。第二个例子是一个非常坏的例子,从另一个角度看,你会这样结束:汽车类:私人引擎,私人车轮,私人座椅“has-a”不应该是继承。我使用私有继承来表示“在的temrs中实现”。它实际上意味着“is-a”但作为一种黑客行为。就像你重复使用了一段不应该产生这些后代的代码,但是嘿……这是一个不使用私有继承的好例子。你是公开还是私下派生不可复制真的不重要,因为复制构造函数和赋值操作符都是私有的。正如@litb所说的在他的回答中,私有派生阻止用户使用指针或对不可复制类型的引用引用my_non_copyable_类型的实例。是的,这也阻止用户通过指向该不可复制类型的指针进行删除。如果我们要阻止接口或成员探索第三个调用方,我们是否应该简单地将基类成员设为D函数是受保护的吗?考虑一下:一个圆是椭圆,但是公共继承不是IS-A关系,尽管我们经常这样称呼它。圈确实是椭圆。不确定你的意思。在很多情况下,这是一个可行的选择。但是如果你最后得到一个“可怕的死亡钻石”,那么编译器不会帮助你(具有虚拟继承)。,你必须自己解决这个问题。