2012-05-11 30 views
8

大家好,我對模板和多態性有疑問。根據定義,多態性提供了代碼的可重用性,從某種意義上說,模板允許用戶通過提供具有不同數據類型的泛型編程來使用相同的代碼。那麼在模板上使用多態性有什麼好處。這可能是一個愚蠢的問題,但我很想知道確切的區別。模板和多態性有什麼區別

+1

模板提供靜態/編譯時多態性。而虛擬主義提供動態多態性。 –

+1

有什麼不同?一切。多態性甚至沒有遠程代碼的可重用性。模板是。 –

+1

@MooingDuck:多態確實允許代碼重用。舊代碼(針對多態基類寫)使用新代碼(寫入相同的基類)。 –

回答

11

你似乎誤解了多態是什麼。

多態性,其核心與派生類無關。多態性僅僅意味着使用某種類型的能力,而不知道它的一切。多態性不是使用具體類型,而是依賴某種形式的原型來定義它需要的類型。任何適合該原型的類型都被接受。

運行時多態性,在C++中,通過從包含虛擬函數的基類派生的類提供。基類和虛函數形成多態原型。編寫接受調用這些虛函數的基類的代碼將接受任何從基類派生的類實例。

編譯時多態性多態性這種情況發生......在編譯時)這意味着,編譯器必須知道是怎麼回事。您可能已經針對多態原型編寫了C++代碼,但編譯器並不在意。你會得到特定的具體類型後編譯。

編譯時多態是由C++中的模板提供的。模板函數或類可以採用符合原型的任何類型,通常稱爲「概念」。不同於基類和虛函數,原型是:原型由類型如何是由模板函數/類使用限定。

如果你有這樣的模板函數:

template<typename T> 
void Stuff(T &t) 
{ 
    t.call(15); 
} 

有上T隱含要求。這個要求是它有一個叫做call的成員函數。這個成員函數必須有一個可以用整數值調用的重載。

這意味着任何類型,恰巧適合這個原型可以使用。

模板多態性比繼承多態性更廣泛的,因爲它可以用的​​類型更廣泛的陣列中使用。一個類型必須專門爲使用繼承多態而設計;你必須從一個類中派生出來。一個類型可以非破壞性地(即:你不必改變類型本身)適應模板多態性。即使moreso如果你的模板原型精心設計:

template<typename T> 
void Stuff(T &t) 
{ 
    call(t, 15); 
} 

所有這個版本的Stuff要求是,有一些功能,需要一個T&和一個整數值。如果我想要使用某種類型的Stuff,我所要做的就是在合適的名稱空間(即定義類型的名稱空間)中定義一個call函數。這將工作得很好。所有沒有修改類型本身。

當然,編譯時多態性是......編譯時。如果我想要一些用戶輸入或數據文件來選擇多態類型,模板不會幫助很多(儘管類型刪除是一種基於模板的技術,可以提供幫助)。運行時多態的主要好處是它確實是運行時。

另一個好處是它的原型更精確。一切都是關於繼承的明確陳述。基類中的虛函數接口已經清晰地展現出來。編譯器會阻止您嘗試錯誤地使用該基類(調用它不存在的方法)。事實上,一個體面的IDE將指導你的代碼,以便你只能看到基類中的方法。

模板多態性更隱含。由於C++沒有辦法將特定的模板函數/類放入某個類型的原型,所以很容易在模板類型上意外調用某些您不應該使用的東西。當您嘗試使用不適合原型的類型時,編譯器只會檢測到這一點。即使這樣,你通常會得到一個巨大的錯誤(取決於你的模板代碼嵌套深度),這使得很難知道問題出在哪裏。

實現隱式模板多態原型也很困難,因爲它沒有被拼寫出來。實現派生類需要遍歷基類,查看所有虛函數並實現它們。這樣做對於模板原型來說要困難得多,除非有文檔說明它在哪裏。如果你沒有實現某些東西,你會再次得到一個錯誤的答案,這個問題通常會少於即將發佈的問題。

+1

「這個成員函數必須有一個可以用整數值調用的重載。」 - 那個用'int'的調用一定不能模棱兩可,也可能是我忘記的其他一些條件。這就是爲什麼多態原型通常以「這個表達式必須具有以下屬性:......」來記錄。如果你試圖按照哪些函數和重載*存在的方式來記錄它,那麼你會遇到各種各樣的邊界情況。 –

相關問題