一直覺得模板類是特別神奇的東西,它可以構造出不同類型的對象,使代碼更加的靈活。這個過程就是類模板的實例化。
成都創(chuàng)新互聯(lián)成立以來不斷整合自身及行業(yè)資源、不斷突破觀念以使企業(yè)策略得到完善和成熟,建立了一套“以技術為基點,以客戶需求中心、市場為導向”的快速反應體系。對公司的主營項目,如中高端企業(yè)網(wǎng)站企劃 / 設計、行業(yè) / 企業(yè)門戶設計推廣、行業(yè)門戶平臺運營、成都App定制開發(fā)、手機網(wǎng)站制作設計、微信網(wǎng)站制作、軟件開發(fā)、服務器托管等實行標準化操作,讓客戶可以直觀的預知到從成都創(chuàng)新互聯(lián)可以獲得的服務效果。我們使用類的模板寫一個stack類:
#include#include"Seqlist1.h" using namespace std; template class Container = Seqlist> class Stack { public: void Push(const T& x) { _con.Pushback(x); } void Pop() { _con.Popback(); } bool Empty() { return Size() == 0; } size_t Size() { return _con.Size(); } T& Top() { size_t size = Size(); assert(size > 0); return _con[size - 1]; } void print() { _con.Print(); } T& operator[](size_t index) { return _con[index]; } protected: Container _con; };
其中我們可以傳入不同類型的T,class Continer是類型T的一個容器,這里默認是用自定義的一個順序表來當容器。編譯器就會構造出不同的代碼出來。
這樣的實現(xiàn)方式是在類內定義成員函數(shù),并把整個類放在.h中,這種方式叫做類模板的包含模式。這樣的定義方式是有好處的,要使用Stack這個類,只要在頭文件內包含類體就可以了,編譯器很容易就可以找到類的定義。當然這種方式是有弊端的,如果一個類的成員函數(shù)個數(shù)很多并且很復雜,無疑在你去閱讀或者修改定義的時候會讓人很頭疼,不能快速找到成員函數(shù)的定義。
還好C++提供了另外一種方式——將成員函數(shù)的聲明放在類體內.h中,將函數(shù)的定義放在.cpp中,就相當與類外定義,我們把這種方式叫做類模板的分離模式。這樣寫出來的代碼是很美觀的,并且易于修改。
//.h文件 #include#include"Seqlist1.h" using namespace std; template class Container = Seqlist> class Stack { public: void Push(const T& x); void Pop(); bool Empty(); size_t Size(); T& Top(); void print(); T& operator[](size_t index); protected: Container _con; }; //.cpp文件 //類外定義 template class Container = Seqlist> void Push(const T& x) { _con.Pushback(x); } template class Container = Seqlist> void Pop() { _con.Popback(); } template class Container = Seqlist> bool Empty() { return Size() == 0; } template class Container = Seqlist> size_t Size() { return _con.Size(); } template class Container = Seqlist> T& Top() { size_t size = Size(); assert(size > 0); return _con[size - 1]; } template class Container = Seqlist> void print() { _con.Print(); } template class Container = Seqlist> T& operator[](size_t index) { return _con[index]; }
類模板的分離模式就會牽扯出一些問題,比如說編譯器在構造對象的時候它怎么找函數(shù)的定義的,因為函數(shù)的定義是在.cpp文件中的。這就是類模板的分離編譯問題。
假設我們stack類是放在stack.h中的,成員函數(shù)的定義放在stack.cpp中的,然后類的調用放在main.cpp中,并且在main.cpp中包含了stack.h。
按照我們通常的思路:
編譯main.cpp時,編譯器不知道f(f是成員函數(shù)中的任意一個函數(shù))的實現(xiàn),所以當碰到對它的調用時只是給出一個指示,指示連接器應該為它尋找f的實現(xiàn)體。這也就是說main.obj中沒有關于f的任何一行二進制代碼。
編譯test.cpp時,編譯器找到了f的實現(xiàn)。于是乎f的實現(xiàn)(二進制代碼)出現(xiàn)在test.obj里。
連接時,連接器在test.obj中找到f的實現(xiàn)代碼(二進制)的地址(通過符號導出表)。然后將main.obj中懸而未決的call XXX地址改成f實際的地址,pofect。
但是當你編譯的時候,編譯器就會報鏈接錯誤,找不到成員函數(shù)的定義。說明我們的思路是錯誤的。對于模板,在沒有實例化出對象之前是不會被編譯成二進制代碼的,而實例化是在程序運行的時候(也就是用到模板的時候)才實例化出對象,實例化是在編譯器對代碼進行編譯的后面才發(fā)生的。這樣問題就迎刃而解了,我們得手動的在main中包含.cpp文件,讓編譯器知道有函數(shù)的定義,這樣編譯器就不會報錯了。
這里有必要提醒(總結)一下的是:
如果你的類不是用模板實現(xiàn)的,就不會有分離編譯的問題,也就是說,即使你的類的成員函數(shù)是在類外定義的也不用include .cpp文件,不管你用沒用到都會實例化出代碼出來,就會編譯成二進制文件,在鏈接時就會鏈接起來。
如果你的類是模板類,并且想要在類外定義成員函數(shù),就必須include .cpp文件。
另外有需要云服務器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。