2011-07-12 44 views
17

在很多情況下,這個問題甚至不會自問,因爲有時繼承會提供模板無法提供的必要功能。例如,當我需要通過一個基類型(多態)解決不同類型時,我需要使用繼承。什麼時候應該使用模板而不是繼承,反之亦然?

但是,有些情況下可以通過繼承和模板來解決問題。

取的代碼的某些部分的示例策略圖案狀的參數化:

文件解析器的

的一個解決方案可能看起來像這樣:

class FileParser 
{ 
    //... 
    public: 
     void Parse(ParsingAlgorithm* p); 
    //... 
} 

void FileParser::Parse(ParsingAlgorithm* p) 
{ 
    m_whatevertypeofvaluesineed = p->Parse(whateverparametersyouneed); 
} 

其中ParsingAlgorithm是一個抽象基類,它提供了一些基本的方法和需要由喜歡爲FileParser類實現特定解析器的人繼承。

然而,同樣可以很容易地實現使用模板:

template <class Parser> 
class FileParser 
{ 
    //... 
    public: 
     void Parse() 
     { 
      m_whatevertypeofvaluesineed = m_parser.Parse(whateverparametersyouneed); 
     } 

    private: 
     Parser m_parser; 
    //... 
} 

是否有我可以用它來決定是否使用模板或繼承的一些一般的規則?還是應該儘可能簡單地使用模板,以避免虛擬功能之類的運行時間開銷?

+0

有點重複[可以CRTP完全替代較小設計的虛擬功能嗎?](http://stackoverflow.com/questions/6613779/can-crtp-completely-replace-virtual-functionality-for-smaller-designs) – iammilind

回答

17

如果您在編譯時知道要操作哪些對象,那麼使用模板進行靜態多態性往往是最快的方法,並且它會生成更簡潔一點的代碼(不需要顯式繼承) 。它也可以更通用,因爲您不受限於強大的類層次結構。

如果你想運行時多態性,那麼你別無選擇,只能使用指針,繼承和虛擬函數的輕微開銷。

我自己的看法:

  • 可能時,它的舒適
  • 使用繼承來factorise代碼(但不具有異質性集合),但要小心使用切割模板。
  • 不要擔心虛擬呼叫
  • 有時候你別無選擇,你想hetergenous收集周圍的疼痛拖着使用指針
4

模板提供編譯時多態性,而不是通過繼承提供運行時多態性。我比較喜歡使用模板。

這篇關於Templates and Inheritance的文章詳細解釋了它。

-1

我的建議是既不使用在這種情況下,併爲每種文件類型使用單獨的功能;

Stream stream = open(filepath); 

    Image image = ParseBMP(stream); 
    // ...or 
    Image image = ParseJPG(stream); 

沒有必要讓事情變得比現在更復雜。

+0

你是對的,但我的例子應該是可能出現「繼承vs模板」問題的一種簡單例子。 – TravisG

+0

我不同意。使用不同的功能是反對開放主體http://en.wikipedia.org/wiki/Open/closed_principle –

+0

從來沒有聽說過這個校長,但它似乎對我有害。 –

3

模板通常在運行時具有更好的性能,因爲更多的性能問題工作是在編譯時完成的。另一方面,它們可能更復雜,因此難以編寫和理解。所以,最好在的時候使用它們,而不要使整個解決方案過於複雜。

對於你的例子,它們並不完全功能等價的:第一個變體允許要求您在運行時創建一個解析器的實例,而第二個變體需要的時候,他寫道碼必須由程序員選擇的解析器。

相關問題