C++中模板函式及模板類的使用(下)
在使用模板類時,一般會將類定義及成員變數和成員函式的宣告放在h標頭檔案中,而將成員函式的定義放在cpp執行檔案中。在編譯程式時可能會出現如下錯誤提示
errorLNK2019: 無法解析的外部符號"public:void __thiscall Stack<int,10>::push(int)"([email protected][email protected][email protected]@[email protected]),該符號在函式_wmain中被引用
該錯誤提示的含義是編譯器只找到了Stack模板類的push()成員函式的宣告,而未能找到該成員函式的定義。產生該錯誤的原因是,在使用模板時,編譯器必須能夠訪問定義模板的原始碼當呼叫函式模板或類模板的成員函式的時候,編譯器需要函式定義,需要那些通常放在原始檔中的程式碼。而模板類的成員函式與普通類的成員函式不同,編譯器不能從它對應的h標頭檔案直接找到cpp執行檔案。
標準C++為編譯模板程式碼定義了兩種模型。一種是“包含編譯模型”,另外一種是“分別編譯模型”。
1 包含編譯模型
包含編譯模型就是在h標頭檔案中包含cpp執行檔案。編譯器在h標頭檔案找到模板類成員函式宣告的同時,就能夠找到該函式的定義了。實現的方法為在在h標頭檔案中的模板類定義之後加入對cpp執行檔案的包含。
template<class T,int MAXSIZE>
class Stack{
.......
};
#include"Stack.cpp"
在使用該模型進行模板編譯時,添加了如上程式碼後,編譯器會報如下錯誤
errorC2995: “voidStack<T,MAXSIZE>::push(T)”: 函式模板已經定義
主要原因是在h標頭檔案中包含了cpp執行檔案,對成員函式進行了定義;而cpp執行檔案又包含在專案中,再次對成員函式進行了定義,所以會有“函式模板已經定義”的錯誤資訊。可以將模板類對應的cpp執行檔案從專案中移除,注意是“移除”而不是“刪除”。
2 分別編譯模型
分別編譯模型就是告訴編譯器去哪裡找類模板成員函式的定義。通過export關鍵字實現。export關鍵字能夠指明給定的定義可能會需要在其它檔案中產生例項化。在一個程式中,一個模板只能定義為匯出一次。在模板類對相應的cpp執行檔案中,有如下程式碼
template<typename T> void Queue<T>::push(constT&)
{
.......
}