實現C++模板類標頭檔案和實現檔案分離的方法
如何實現C++模板類標頭檔案和實現檔案分離,這個問題和編譯器有關。
引用<<C++primer(第四版)>>裡的觀點:1)標準C++為編譯模板程式碼定義了兩種模型:“包含”模型和“分別編譯”模型。2)所有編譯器都支援“包含”模型,某些編譯器支援“分別編譯”模型。
第一種方法:按C++primer中的“包含”模型,在定義模板類的標頭檔案中的末行用語句:#include "template_compile.cpp"
在類模板標頭檔案template_compile.h中:
[cpp] view plaincopyprint?-
template<class T>
- class base
- {
- public:
- base() {};
- ~base() {};
- T add_base(T x,T y);
- };
- #include "template_compile.cpp"
在類模板的實現檔案template_compile.cpp中:
[cpp] view plaincopyprint?- template<class T>
- T base<T>::add_base(T x,T y)
- {
- return x+y;
- }
在使用模板的測試檔案use_template.cpp中:
- #include<iostream>
- #include "template_compile.h"
- using namespace std;
- void main()
- {
- base<int> bobj;
- cout<<bobj.add_base(2,3)<<endl;
- }
這種方法不能通過編譯,"template_compile.cpp"檔案不能"看見"“template_compile.h"檔案。
然而:如果我把類模板的實現檔案裡程式碼放在類模板的標頭檔案中,註釋掉:#include "template_compile.cpp",編譯和執行不會有任何錯誤。理論上”把類模板的實現檔案裡程式碼放在類模板的標頭檔案中“和”在定義模板類的標頭檔案中的末行用語句:#include "template_compile.cpp" “是一致的,但編譯器就是通不過。
實驗證明:VC9.0不支援C++primer中所說的“包含”模型。
第二種方法:bruceteen提出的:使用define
在類模板標頭檔案template_compile.h中:
[cpp] view plaincopyprint?- template<class T>
- class base
- {
- public:
- base() {};
- ~base() {};
- T add_base(T x,T y);
- };
- #define FUCK
- #include "template_compile.cpp"
在類模板的實現檔案template_compile.cpp中:
[c-sharp] view plaincopyprint?- #ifdef FUCK
- template<class T>
- T base<T>::add_base(T x,T y)
- {
- return x+y;
- }
- #endif
測試檔案不變。
實驗證明:在VC9.0中,這種方法可以實現類模板標頭檔案和實現檔案的分離
方法三:
在類模板標頭檔案template_compile.h中:
[cpp] view plaincopyprint?- template<class T>
- class base
- {
- public:
- base() {};
- ~base() {};
- T add_base(T x,T y);
- };
在類模板的實現檔案template_compile.cpp中:
[c-sharp] view plaincopyprint?- #include "template_compile.h"
- template<class T>
- T base<T>::add_base(T x,T y)
- {
- return x+y;
- }
在使用模板的測試檔案use_template.cpp中:使用#include "template_compile.cpp"
[c-sharp] view plaincopyprint?- #include<iostream>
- #include "template_compile.cpp"
- using namespace std;
- void main()
- {
- base<int> bobj;
- cout<<bobj.add_base(2,3)<<endl;
- }
實驗證明:在VC9.0中,這種方法可以實現類模板標頭檔案和實現檔案的分離。
另外實驗證明:VC9.0不支援“分別編譯”模型。
C++中每一個物件所佔用的空間大小,是在編譯的時候就確定的,在模板類沒有真正的被使用之前,編譯器是無法知道,模板類中使用模板型別的物件的所佔用的空間的大小的。只有模板被真正使用的時候,編譯器才知道,模板套用的是什麼型別,應該分配多少空間。這也就是模板類為什麼只是稱之為模板,而不是泛型的緣故。
既然是在編譯的時候,根據套用的不同型別進行編譯,那麼,套用不同型別的模板類實際上就是兩個不同的型別,也就是說,stack<int>和stack<char>是兩個不同的資料型別,他們共同的成員函式也不是同一個函式,只不過具有相似的功能罷了。&amp;lt;img src="https://pic2.zhimg.com/1772de8abdd112a50e533e3c018535a1_b.jpg" data-rawwidth="749" data-rawheight="308" class="origin_image zh-lightbox-thumb" width="749" data-original="https://pic2.zhimg.com/1772de8abdd112a50e533e3c018535a1_r.jpg"&amp;gt;如上圖所示,很簡短的六行程式碼,用的是STL裡面的stack,stack&amp;amp;lt;int&amp;amp;gt;和stack&amp;amp;lt;char&amp;amp;gt;的預設建構函式和push函式的入口地址是不一樣的,而不同的stack&amp;amp;lt;int&amp;amp;gt;物件相同的函式入口地址是一樣的,這個也反映了模板類在套用不同型別以後,會被編譯出不同程式碼的現象。如上圖所示,很簡短的六行程式碼,用的是STL裡面的stack,stack<int>和stack<char>的預設建構函式和push函式的入口地址是不一樣的,而不同的stack<int>物件相同的函式入口地址是一樣的,這個也反映了模板類在套用不同型別以後,會被編譯出不同程式碼的現象。
所以模板類的實現,脫離具體的使用,是無法單獨的編譯的;把宣告和實現分開的做法也是不可取的,必須把實現全部寫在標頭檔案裡面。為了清晰,實現可以不寫在class後面的花括號裡面,可以寫在class的外面。