2011-08-31 49 views
25

我一直在尋找這一個,對此的共同反應似乎是沿着「他們是不相關的,一個不能取代另一個」的路線。但是,如果你正在採訪,並被問及「你什麼時候使用模板而不是繼承,反之亦然?」什麼時候使用模板與繼承

+15

這是「不是一個真正的問題」?近乎快樂的觸發手指刺激我。 –

+2

如果你在採訪中聽到這個問題,現在是時候說再見了,因爲他們只是在浪費你的時間;你現在也和我們一樣。 –

+1

這是一個愚蠢的面試問題。充其量,這是錯誤的方式。你不應該問「你什麼時候使用工具X」。你應該問,「這是問題J.你如何解決它?」答案可能是「工具X」。 – tenfour

回答

3

當您想要保留類型安全性或想要避免虛擬分派時,在基礎(或組合)中使用模板。

+2

事實上,我懷疑通過[CRTP](http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)避免虛擬調度是面試官尋找的內容。 – ildjarn

13

「常見的答案」是錯誤的。在「Effective C++」中,Scott Meyers在第41項中說:

項目41:瞭解隱式接口和編譯時多態性。

邁爾斯接着總結:

  • 兩個類和模板支持接口與多態。
  • 對於類,接口是明確的,並以函數 爲中心簽名。多態性通過虛函數在運行時發生。
  • 對於模板參數,接口是隱式的並且基於有效的 表達式。在通過模板 實例化和函數重載解析進行編譯期間發生多態性。
+0

他也犯了錯字嗎? :P –

+1

嘿嘿。我無法找到剪切和粘貼的源代碼... – Gnawme

+0

我建議大家閱讀該章節,這將清楚你需要從介紹中使用:) – Hame

1

模板適用於定義可處理多種不相關對象類型的接口。對於容器類來說,模板是非常有意義的,因爲它在必要時概括了容器中的對象,但保留了類型信息。

在繼承的情況下,所有參數必須是已定義的參數類型,或者從其中擴展。因此,當方法在正確地具有直接層次關係的對象上操作時,繼承是最佳選擇。

如果繼承錯誤地應用,那麼它需要創建過於複雜的無關對象的類層次結構。代碼的複雜性會增加一小部分。如果是這種情況,那麼使用模板。

42

我看到的方式是模板和繼承是字面上正交的概念:繼承是「垂直的」,並且從抽象到更具體。形狀,三角形,等邊三角形。

另一方面,模板是「水平的」並且定義了並行的代碼實例,它們彼此不知道任何東西。對整數進行排序與​​排序雙精度和排序字符串形式上相同,但這些是三個完全不同的功能。他們都從遠處「看」着相同的東西,但是它們沒有任何關係。

繼承提供了運行時抽象。模板是代碼生成工具。

因爲這些概念是正交的,所以它們可以愉快地一起用來實現一個共同的目標。我最喜歡的例子是類型擦除,其中類型擦除容器包含一個虛擬基指針指向實現類,但有任意多個具體實現由模板派生類生成。模板代碼生成用於填充繼承層次結構。魔法。

+1

我喜歡這個解釋。這裏的英語比其他英語要簡單一點。 – Brent212

+1

嗯,我不是這方面的專家,這就是爲什麼我找到了這個答案,但正如你所描述的那樣,在我看來,模板解決了像mixin這樣的複雜固有系統缺乏C++的問題(例如一個問題,例如,由Go解決優雅)。如果整數和雙精度和字符串沒有共同之處,但需要排序,則三者應以某種方式擴展「可排序」特性。 – pistacchio

+1

@pistacchio:我不會稱複雜的繼承爲「解決方案」。模板以更好的方式提供排序功能,因爲排序者不需要知道它正在排序。複雜的繼承通常會導致當你用一種強制的思維方式工作時,一切都必須是一個繼承層次結構,事實上這很少適用。 Go的方法很簡單,但限制性更強,效率更低。 Go希望成爲小型語言是合適的。 –

0

模板描述了一種算法,例如決定一個類的兩個對象之間的比較結果或對它們進行排序。操作對象的類型(類)會有所不同,但操作或邏輯或步驟等在邏輯上是相同的。

另一方面,繼承被子類用於擴展或更具體的父母功能。 希望有道理