2008-12-17 129 views
50

在C++中,我想不出一个案子,我想继承私有/保护以免受 基类:为什么我们实际上需要C++中的私有或受保护的继承?

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

是否真的有用吗?

+4

考虑一下:一个圆是一个椭圆,但[Circle不能代替Ellipse](http://stackoverflow.com/questions/7602102/teach-dynamic-polymorphism-with-simple-example/7677015#7677015),公共继承是***不是***是一种关系,虽然我们经常这么称呼它。 – spraff 2012-01-04 11:43:26

+5

圆确实是一个椭圆。不明白你的意思? – 2013-11-28 09:21:17

回答

41

当您希望访问某些基类的成员,但没有将它们暴露在类接口中时,它非常有用。私有继承,也可以看作是某种组成: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 
}; 

但是,这样做的这种方式有几个缺点:

  • 你的意图是那么清楚
  • 它可以导致滥用多重继承
  • 它打破了引擎类的封装,因为你可以访问它的protected成员
  • 你被允许重写引擎的虚拟方法,这是你不想要,如果你的目标是一个简单的组合
38

Private在很多情况下都可以使用。其中之一是政策:

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*类型的指针指向我们的对象,我们私下得出。这不仅包括不可复制的,也包括许多其他类别(政策是最常见的)。

+1

因为拷贝构造函数和赋值操作符都是私有的,所以如果你公开或私下地获取非拷贝,真的没关系。 – Marcin 2008-12-18 14:53:16

+6

由于@litb在他的回答中声明,私下导出会阻止用户使用指针或对不可复制的指针进行引用my_non_copyable_type的实例。 – 2008-12-18 15:26:23

+2

是的,这也可以防止用户通过指向该不可复制的指针进行删除。 – 2008-12-19 12:30:16

15

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

Sutter on the topic。他解释了何时选择非公有继承来控制实施细节。

3

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

0

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

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

受保护的传承是非常有用的。

-1

我一次实现了这些数据结构类:

  • 链表
  • 通用阵列(摘要)
  • 简单的数组(从通用阵列继承)
  • 大阵列(从通用阵列继承)

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

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

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

我意识到有可能情况下,当已经-一个不因过分热心运用“保护”工作,但它是更好地修复损坏的类,而不是突破一个新的类。

相关问题