2008-12-17 127 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的答案,它提供了這種反模式的一個完美例子。

我意識到有可能情況下,當已經-一個不因過分熱心運用「保護」工作,但它是更好地修復損壞的類,而不是突破一個新的類。

相關問題