最近在看 C++ 的方法和類別範本,我就在想 C# 中也是有這個概念的,不過叫法不一樣,人家叫模板,我們叫泛型,哈哈,有點意思,這一篇我們來聊聊它們底層是怎麼玩的?
畢竟 C++ 是相容 C 語言,而 C 是過程式的玩法,所以 C++ 就出現了兩種模板型別,分別為:函數模板
和 類別範本
,下面簡單分析一下。
玩之前先看看格式: template <typename T> rettype funcname (parameter list) { }
。
說實話,我感覺 C++ 這一點就做的非常好,人家在開頭就特別強調了,這是一個 template
,大家不要搞錯了,按照這個格式,我們來一個簡單的 Sum
操作,參考程式碼如下:
#include <iostream>
//求和函數
template <typename T> T getsum(T t1, T t2) {
return t1 + t2;
}
int main() {
int sum1 = getsum<int>(10, 10);
long sum2 = getsum<long>(20, 20);
printf("output: int:sum=%d, long: sum=%ld", sum1, sum2);
}
接下來我就很好奇,這種玩法和 普通方法
呼叫有什麼不同,要想找到答案,可以用 IDA
去看它的靜態組合程式碼。
從靜態反組合程式碼看,當前生成了兩個函數符號分別為: j_??$getsum@H@@YAHHH@Z
和 j_??$getsum@J@@YAJJJ@Z
,現在我們就搞清楚了,原來一旦給 模板
指定了具體型別,它就生成了一個新的函數符號。
乍一看這句話好像沒什麼問題,但如果你心比較細的話,會發現一個問題,如果我呼叫兩次 getsum<int>
方法,那會生成兩個具體函數嗎? 為了尋找答案,我們修改下程式碼:
int main() {
int sum1 = getsum<int>(10, 10);
int sum2 = getsum<int>(15, 15);
}
然後再用 IDA 檢視一下。
哈哈,可以發現這時候並沒有生成一個新的函數符號
,其實往細處說:j_??$getsum@H@@YAHHH@Z
是函數簽名
組合出來的名字,因為它們簽名一致,所以在編譯階段必然就一個了。
首先看下類別範本的格式:template <typename T1, typename T2, …> class className { };
還是那句話,開頭一個 template
暴擊,告訴你這是一個模板