2010-01-24 68 views
4

假設我有一類ENGIN,我從ENGIN類私人繼承和組合,哪一個最好,爲什麼?

class engin 
{ 
    public: 
     engin(int nobofcylinders); 
     void start(); 
}; 
class car:private engin 
{ 
    public: 
     car():e(8){} 
     void start() 
     { 
      e.start(); 
     } 
    private: 
     engin e; 
}; 

現在同樣可以通過組合物來實現繼承一個類車,問題是計算策略將是最好的,在編程時大多使用,爲什麼???????

回答

4

我寧願將繼承想象成derived is a kind of base,這基本上意味着公有繼承。在私人繼承的情況下,它更像是derived has a base,恕我直言,聽起來不正確,因爲這是恕我直言的工作組成不是任何形式的繼承。那麼,由於私人繼承和構成在邏輯上本質上意味着同樣的事情,哪一個可以選擇?通過你發佈的例子,我肯定會去寫作。爲什麼?我傾向於把各種各樣的繼承想象爲一種關係,並且你發佈的例子中,我想不出一種我可以說a car is kind of an engine的情況,它根本就不是。它的確如同a car has an engine,那麼爲什麼汽車會繼承引擎?我沒有看到任何理由。

現在的確有些情況下,私有繼承是好的,即boost::noncopyable,它的ctor/dtor被保護,你很難實例化它,事實上,因爲我們希望我們的類到have a noncopyable part,那就是唯一的辦法就是去。

一些風格指南(例如google c++ style guide)甚至建議不要使用私有繼承,原因與我已經寫過的類似 - 私有繼承有點混亂。

希望它有幫助。

+0

雅這是我期待的答案。謝謝你的先生。 – 2010-01-24 11:17:44

+0

@Zia不要批評這個答案,但是SO的目的不是爲提問者提供他們「期望」的答案,而是提供技術上正確的答案。 – 2010-01-24 12:21:57

5

如果你想比較私人繼承與組合,請閱讀http://www.parashift.com/c++-faq-lite/private-inheritance.html#faq-24.3。我不認爲私人繼承是好的。


一個Car有-的Engine,但Car是 - 不的Engine,所以它應該是與組成做得更好。

繼承對於「is-a」關係是有用的,例如,一個Bus是-一個Car,一個Car是-一個vehicle

組合物用於 「具有-a」 關係,例如有用一個Car具有Wheel -s,一個Car具有安Engine

所以一個邏輯碼應該是這樣

class Car : public Vehicle { 
    Engine engine; 
    Wheel wheels[4]; 
    ... 
}; 
+2

私有繼承不*模擬一個有一個關係。 「繼承」這個名字在這裏只是誤導。相反,它模擬了一種被實施的條件關係(這在這裏也不合適)。 – 2010-01-24 10:11:56

+0

+1,幾乎沒有什麼可說的:) – Frunsi 2010-01-24 10:12:02

+2

那麼,私有繼承不會創建一個is-a關係。我同意作文更好。 – 2010-01-24 10:13:01

6

組合物是優選的主要有兩個原因:

  • 組成的東西可以有名字
  • y ou可以撰寫多個同類型的東西
+1

我傾向於同意 - 但在涉及策略類(分配器等)時,私有繼承是C++中已確立的模式。 – 2010-01-24 10:13:32

+1

還有一個主要原因:繼承,公共或私人,比組合更緊密的耦合。失去聯結是首選。 – sbi 2010-01-24 10:50:34

+0

@sbi:尤其是因爲作文可以通過Pimpl使用:) – 2010-01-24 13:30:39

3

儘管名稱不同,私人繼承並不是真正的繼承 - 至少不是從(外部的)外部來看它的重要性。

因此,適用不同的規則。在C++中,私有繼承被稱爲對「關係實現」進行建模。因此,這是在堆方面實現優先級隊列,看起來是這樣的:

template <typename T, typename Comp = std::less<T> > 
class priority_queue : private heap<T, Comp> { 
    // … 
}; 

就個人而言,我沒有看到這種模式的優勢,尼爾已經指出,在大多數情況下,組成實際上比私有繼承有優勢。

其中一個的優勢存在,但是:由於它是這樣一種既定模式,私有繼承的含義對於經驗豐富的C++程序員來說立即就很清楚;上面的代碼會告訴他們,優先級隊列是以堆的形式實現的 - 如果這個類碰巧發生了堆使用作爲它的一個成員,這並不明顯。

私有繼承在C++中主要用於策略類。典型的例子是分配器,其決定容器類如何在內部管理存儲:

template <typename T, typename A = std::allocator<T> > 
class vector : private A { 
    // … 
}; 

沒有傷害。但是再一次,這也可以通過使用合成來完成。

3

通常,成分是首選(其他人,放棄的主要原因),但私有繼承允許的事情無法用成分來完成:

  • 大小爲零的基類優化(基類大小爲零不會增加一個類的大小,零大小的成員將會),它的背後原因使用的政策類通常沒有數據成員

  • 控制初始化順序,以便什麼是構成在公共基地之前初始化

  • 覆蓋在什麼由

  • 與私人虛擬繼承虛擬成員,確保只有一個,即使一個做到這一點的幾個基地

請注意,由東西了後面兩種用法,基類存在的事實可以在後代中觀察到。

+0

我不喜歡第三點:我更喜歡通過公開繼承的類來覆蓋虛擬方法,並且在構圖中使用這個類。 – 2010-01-24 13:32:11

+0

@Matthieu,這是一個選擇。但是,如果新類的唯一理由是它允許使用組合而不是私有繼承,那麼我可能不會使用它 - 它不能證明有兩個緊密耦合的類。如果不是這樣,那麼這個班級可能有足夠的目的,而不會帶來妨礙私人繼承的事實。 – AProgrammer 2010-01-24 14:30:32

3

組合使用比私人繼承更多。我遵循的一般規則是,除非你有特定的理由使用私有繼承,否則你應該使用組合。

組成擁有私有繼承了許多好處:

  • 你可以有一個特定類別的多個實例。
  • 你不會污染你的班級的名字空間,有一大堆你的班級沒有意義的私人功能。
  • 您可以到
  • 你類較少連接到它的組成比它是一類從
  • 繼承如果你發現你需要換出一個對象的類的對象的部分投行的名字是你在對象的生命週期中已經包含了構圖,你可以用私有繼承來堅持。

組成還有很多其他好處。基本上,它更靈活,更清潔。

雖然有理由使用私有繼承。他們是非常具體的原因,如果你認爲他們適用,你應該仔細考慮你的設計,以確保你必須這樣做。

  • 您可以覆蓋虛擬功能。
  • 您可以訪問受保護的基類成員。
  • 您需要將自己傳遞給想要繼承的類的對象(這通常與重載的虛擬函數結合在一起)。

而且有幾個相當棘手的人還有:

  • 如果您使用的成分爲具有0大小的一類,它仍然佔用空間,但私有繼承它沒有。
  • 您想爲您要私下繼承的類的虛擬基類調用特定構造函數。
  • 如果您想在初始化其他基類之前初始化私有基礎(使用合成,您的類中的所有變量將在您的所有基類都被初始化後)。
  • 使用私有虛擬繼承來確保只有一個事物的副本,即使您有多個擁有它的基類。 (在我看來,使用指針和正常構圖可以更好地解決這個問題。)
1
  • 私有繼承意味着 被實現,在專用條款。它的 通常不如組成,但 它是有道理的時候派生類 需要訪問受保護的基類 成員或需要重新定義 繼承的虛擬功能。

  • 與組合不同,私有 繼承可以使空基優化 。對於努力減少對象大小的圖書館開發人員來說,這可能是重要的 。

Scott Meyers「Effective C++」Third Edition。