今天是個科普文:C++的模板爲什麼要在頭文件(.h)中實現?
模板的用途這個事情其實我沒什麼發言權,實話實說,我寫模板比較少。對於模板的重要性,也是最近才感覺到。至於模板的重要性,這裏也不多說,自己悟。
這裏就舉個函數模板的例子(我們把實現放在.cpp的錯誤例子):
lp_max.h
template <typename T>
T max(const T a, const T b);
lp_max.cpp
template <typename T>
T max(const T a, const T b)
{
if (a >= b) return a;
else return b;}
main.cpp
#include "lp_max.h"
using namespace std;
int main()
{
cout << max(1, 2) << endl;
cout << max('d','b' ) << endl;
cout << max(1.5, 2.5) << endl;
return 0;
}
例子很簡單,不要嫌棄,我們主要講道理。
有些基礎知識的coder都知道,C/C++都是先編譯(compile)、再鏈接(link)(嚴格來說,編譯過程還可以細分,但是與本次說說明問題無關),模板方法的特化過程其實是在編譯(compile)階段完成的,也就是說在編譯過程中,模板被示例爲幾個實際的方法或者類就已經確定了。
鏈接(link)的時候,只會將compile階段生成的目標文件(.o .obj)鏈接起來,生成可執行程序。
回到我們剛纔的例子,我們實現了lp_max.h和lp_max.cpp,然後增加一個main方法去使用,編譯過程如下:
lp_max.cpp的編譯過程是模板方法的特化過程,這個過程會根據其他文件的引入情況去形成對應的函數實現,但是,由於沒有文件引入lp_max.cpp,造成的結果就是,lp_max.cpp看似很正常的編譯成lp_max.o目標文件,實際上,這個文件裏面什麼也沒有,是個空文件。
main.cpp編譯的時候,因爲頭文件引入了lp_max.h,知道有一個函數方法,但是,因爲頭文件中沒有實現,編譯器就假定其他地方會實現可用的方法,於是,標記出main.o需要幾個max方法,並且也編譯通過,等待連接時候,得到需要的max方法實現。
等到真正鏈接的時候,不幸的事情發生了,main.o在生成可執行文件時,找不到max方法的實現,這時候就會出現類似於下面的鬼東西(linux情況類似undefined reference to xxxx):
這時候,問題就暴露出來了,簡單的像一般函數一樣,頭文件.h聲明,.cpp文件實現出現了問題。如果你把模板方法的聲明、實現都放在頭文件lp_max.h,則在編譯出main.o的時候,就會按照需要生成不同的max()方法。
很顯然不是,有一些方法可以將實現抽離出來。但是,從本質上來說,必須保證在編譯的時候,將需要的方法特化出來,才能夠正常通過鏈接。至於抽離的方法,有機會再分享。
本文的公衆號地址爲:C++的模板爲什麼要在頭文件(.h)中實現?,如果有幫助,關注一下。
·END·
有技術,有雞湯,還有碎碎念,盡在