版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、笨鳥先飛學(xué)編程系列-C+高級(jí)特性之模板當(dāng)我們?cè)絹碓蕉嗟氖褂肅+的特性, 將越來越多的問題和事物抽象成對(duì)象時(shí), 我們不難發(fā)現(xiàn):很多對(duì)象都具有共性。 比如 數(shù)值可以增加、減少;字符串也可以增加減少。 它們的動(dòng)作是相似的, 只是對(duì)象的類型不同而已。C+ 提供了“模板”這一特性, 可以將“類型” 參數(shù)化, 使得編寫的代碼更具有通用性。 因此大家都稱模板編程為 “通用編程”或 “泛型編程”。一般而言, 模板分為 函數(shù)模板 和 類模板,下面就讓我們分別來了解一下它們。一、 函數(shù)模板1、 函數(shù)模板的定義和使用定義一個(gè)模板函數(shù)的格式并不復(fù)雜, 如下:template <模板參數(shù)列表>返回類型 函數(shù)
2、名(函數(shù)參數(shù)列表) / code .下面, 讓我們來舉一個(gè)例子來說明 模板函數(shù)的作用和用法(具體代碼見 Exp01)。/ 定義一個(gè)函數(shù)模板, 用來實(shí)現(xiàn)任意類型數(shù)據(jù)的相互交換。template <typename T>/ 聲明一個(gè) T 數(shù)據(jù)類型, 此類型隨 調(diào)用方 類型的變化而變化void swap(T& a, T& b) T tmp = a; a = b; b = tmp; 上面的代碼, 說明了模板函數(shù)的用法。下面再給出調(diào)用的代碼, 我們看看如何使用這個(gè)函數(shù)模板:int main(int argc, char* argv) int nNum1 = 50; int n
3、Num2 = 30; double dfNum1 = 2.1; double dfNum2 = 3.0; char *pszFirst = "Hello " char *pszSec = "world!" swap <int> (nNum1, nNum2);/ 將swap函數(shù)模板實(shí)例化為 int類型的模板函數(shù)再調(diào)用 printf("nNum1 = %d, nNum2 = %drn", nNum1, nNum2); swap<double> (dfNum1, dfNum2); printf("dfNum
4、1 = %f, pszSec = %frn", dfNum1, dfNum2); swap<char *> (pszFirst, pszSec); printf("pszFirst = %s, pszSec = %srn", pszFirst, pszSec);return 0;具體的執(zhí)行結(jié)果如下:我相信,如果你是第一次見到模板的代碼,那你一定也會(huì)像我一樣好奇,這個(gè)功能是怎么實(shí)現(xiàn)的,它是怎么做到讓一段代碼來兼容各種類型的呢?當(dāng)我要反匯編該EXE得時(shí)候,無意間查看了下編程生成的map文件,讓我看到了如下的內(nèi)容: Address Publics by Va
5、lueRva+BaseLib:Object0001:00000140?swapYAXAAH0Z00401140 f iExp01.obj0001:00000190?swapYAXAAN0Z00401190 f iExp01.obj0001:000001f0?swapYAXAAPAD0Z004011f0 f iExp01.obj由此可見, 我們編寫的void swap(T& a, T& b), 只是一個(gè)“函數(shù)模板”, 要使用它需要先將它實(shí)例化為一個(gè)“模板函數(shù)”(如:swap <int>)。編譯器在編譯此程序的時(shí)候,為每個(gè)調(diào)用此模板的代碼生成了一個(gè)函數(shù)。而且在后期的使用
6、過程中,更加讓我認(rèn)識(shí)到:a、 函數(shù)模板 并不是函數(shù),它僅在編譯時(shí)根據(jù)調(diào)用此模板函數(shù)時(shí)傳遞的實(shí)參類型來生成具體的函數(shù)體!若 函數(shù)模板沒有被調(diào)用責(zé)不生成任何代碼也不對(duì)模板代碼作任何語法檢查。b、 在模板類型參數(shù)中, 實(shí)參與形參要求嚴(yán)格匹配,它不會(huì)進(jìn)行任何的類型轉(zhuǎn)換。c、 對(duì)于函數(shù)模板,我們?cè)谡{(diào)用時(shí)不一定必須先進(jìn)行將它實(shí)例化為一個(gè)函數(shù)也是可以的,編譯器會(huì)自動(dòng)的識(shí)別模板的類型。(換句話說:Exp01中的代碼可以直接使用swap, 而不需要<>)2、 函數(shù)模板的重載當(dāng)編寫的一個(gè)模板無法滿足所有需要的情況時(shí),就需要對(duì)模板進(jìn)行重載(或叫 特例化),例如:我們編寫了一個(gè)較大值的模板Max:temp
7、late <typename T>T* const& Max(T const& a, T const& b) return a < b ? b : a;A、 當(dāng)我們需要傳入兩個(gè)指針類型的實(shí)參時(shí),該模板就失效了,需要重載該模板:template <typename T>T* const& Max(T* const& a, T* const& b) return *a < *b ? *b : *a;B、 倘若我們?cè)傩枰容^兩個(gè)字符串大小時(shí),上面兩個(gè)模板都失效了。因?yàn)閏har* 并沒有提供 operator <
8、 運(yùn)行,我們只能通過調(diào)用strcmp庫函數(shù)自己實(shí)現(xiàn)一個(gè)Max模板的特例(見Exp02):const char* Max(const char*& a, const char*& b) return strcmp(a, b) < 0 ? b : a;說明:C+模板機(jī)制規(guī)定,如果一個(gè)調(diào)用,即匹配普通函數(shù),又能匹配模板函數(shù)的話,則優(yōu)先匹配普通函數(shù)。因此,當(dāng)我們模板特例化的時(shí)候,會(huì)先匹配特例化的函數(shù)。二、 類模板1、 基本概念類模板一般應(yīng)用于容器類中,使得容器能夠處理各種類型的對(duì)象,如(詳見Exp03):struct Node Node( int nData = 0 ) m_nD
9、ata = nData; m_pPrev = m_pNext = NULL; int m_nData;/ 數(shù)據(jù)元素 Node* m_pPrev;/ 指向上一個(gè)元素的指針 Node* m_pNext;/ 指向下一個(gè)元素的指針;class CDListprivate: int m_nCount; Node* m_pHead; Node* m_pTail; int m_nMessage;public:CDList();virtual CDList();public:int GetLen() constm_nCount;Node* GetHead() constreturn m_pHead;Node*
10、 GetTail() constreturn m_pTail;public:bool Change(int nIndex1,int nIndex2);void Release();/增加Node* AddTail( int nData );Node* AddHead( int nData );Node* operator(int nIndex);/刪除bool DeleteNode( int nIndex );void PrintAll();/查找Node* FindNode( int nIndex );對(duì)于這樣的鏈表,其節(jié)點(diǎn)的元素只能存放整型數(shù)據(jù)。如果要想讓此雙向鏈表能夠存放任何一種類型的元
11、素,那此時(shí)我們需要的問題與函數(shù)模板就一樣了,將此類修改成類模板,現(xiàn)在先不管類模板的寫法,讓我們按照函數(shù)模板的方法將類修改一下:template <typename T>struct Node Node( T Data ) m_Data = Data; m_pPrev = m_pNext = NULL; Tm_Data; / 通用類型的數(shù)據(jù)元素 Node<T>* m_pPrev;/ 指向上一個(gè)元素的指針 Node<T>* m_pNext;/ 指向下一個(gè)元素的指針;這樣,我們每個(gè)節(jié)點(diǎn)都可以使用通用的類型了,當(dāng)然,對(duì)節(jié)點(diǎn)的處理也一樣得處理。按照這個(gè)樣子將類型參數(shù)化
12、(為節(jié)省篇幅,具體的實(shí)現(xiàn)部分請(qǐng)參考Exp04):template <typename T>class CDListprivate:int m_nMessage;/ 消息號(hào)int m_nCount;/ 鏈表中 元素的數(shù)量Node<T>*m_pHead;/ 鏈表頭指針Node<T>*m_pTail;/ 鏈表尾指針public:CDList();virtual CDList();public:int GetLen() constm_nCount;Node<T>* GetHead() constreturn m_pHead;Node<T>*
13、GetTail() constreturn m_pTail;public:bool Change(int nIndex1,int nIndex2);void Release();/增加Node<T>* AddTail( T Data );Node<T>* AddHead( T Data );Node<T>* operator(int nIndex);/刪除bool DeleteNode( int nIndex );void PrintAll();/查找Node<T>* FindNode( int nIndex );這樣就修改好了,很簡(jiǎn)單吧,貌似類
14、模板沒有什么太多的新語法規(guī)范。完整的模板代碼,大家可以參考Exp04,下面我們總結(jié)一下類模板的一些語法小細(xì)節(jié)。2、 類模板的定義通過上面的一番修改,我相信你一定對(duì)類模板有了一定的了解,下面我們大致的總結(jié)一下類模板的定義格式:Template <typename T>Class 類名/ code,可以使用模板參數(shù)T來指定通用的數(shù)據(jù)類型。正如上面的Exp04中一樣,我們的模板寫好了,但是它不能直接使用,就像函數(shù)模板一樣,我們需要先將模板實(shí)例化成一個(gè)模板類才可以使用。在函數(shù)模板中,編譯器會(huì)針對(duì)我們傳遞的實(shí)參類型等信息自動(dòng)的給我們實(shí)例化函數(shù)模板為模板函數(shù),但是類模板就沒有這么智能了,必須手
15、工實(shí)例化:int main(int argc, char* argv)CDList<int> MyList;/ 將CDList實(shí)例化為一個(gè)int類型,也就是說鏈表中數(shù)據(jù)元素為整型/(20) (80) 100 200 50 60MyList.AddTail(20);MyList.AddTail(80);MyList.AddTail(100);MyList.AddTail(200);MyList.AddTail(50);MyList.AddTail(60);MyList.PrintAll();MyList.Change(0,1);MyList.PrintAll();return 0;程
16、序執(zhí)行結(jié)果:總結(jié):a、 類模板 同樣也不是類,它僅在編譯時(shí)根據(jù)實(shí)例化本模板時(shí)傳遞的實(shí)參來生成具體的類代碼!若 類模板沒有被實(shí)例化也沒有被調(diào)用,那編譯器不會(huì)為本模板生成任何代碼也不對(duì)模板代碼作任何語法檢查。3、 類模板的特化類模板的特化又被叫做類模板的定做,首先讓我們來了解下什么叫作定做。通過上面幾個(gè)小節(jié)的學(xué)習(xí),我相信,大家都知道模板不能直接被使用:必須先給模板傳遞一個(gè)實(shí)參,將它實(shí)例化為一個(gè)模板類,然后才可以用它來定義具體的對(duì)象。這樣就隱含了一個(gè)問題:我們通過給模板傳遞一個(gè)實(shí)參來實(shí)例化的模板類中的代碼都是在模板中定義好的,如果我們不能用與定義好的模板代碼來生成模板類,這時(shí)就需要使用模板的特化,也
17、就是“定做”。比如,我們剛才寫好的雙向鏈表模板中,對(duì)于某一個(gè)類(比如CStudent)來說,不允許添加重復(fù)的節(jié)點(diǎn),但是對(duì)于像普通的int,double等數(shù)據(jù)類型以及其它一些類時(shí),又不需要有這類的限制。這時(shí)我們就需要將此雙向鏈表模板針對(duì)這個(gè)不允許有重復(fù)節(jié)點(diǎn)的類(如:CStudent)進(jìn)行特化,大致代碼如下:template <>class CDList<CStudent>private:int m_nMessage;/ 消息號(hào)int m_nCount;/ 鏈表中 元素的數(shù)量Node<CStudent>*m_pHead;/ 鏈表頭指針Node<CStude
18、nt>*m_pTail;/ 鏈表尾指針public:bool Change(int nIndex1,int nIndex2);void Release();/增加Node<CStudent>* AddTail( CStudent Data );Node<CStudent>* AddHead( CStudent Data );Node<CStudent>* operator(int nIndex);/刪除bool DeleteNode( int nIndex );void PrintAll();/查找Node<CStudent>* FindN
19、ode( int nIndex );Node<CStudent>* CDList<CStudent>:AddTail( CStudent Data )Node<CStudent>* pNewNode = new Node<CStudent>(Data);if ( m_pTail )m_pTail->m_pNext = pNewNode;pNewNode->m_pPrev = m_pTail;if ( m_pTail = NULL )m_pHead = pNewNode;m_pTail = pNewNode;m_nCount+;retu
20、rn pNewNode;由此可知,為CStudent類定做的CDList模板類,就是以CDList<CStudent>為類名重寫一份CDList<CStudent>實(shí)現(xiàn)而拋棄編譯器為我們生成的CDList<CStudent>類。當(dāng)一個(gè)模板擁有多個(gè)模板參數(shù)時(shí),如果我們只對(duì)其部分參數(shù)定做則稱為“局部定做”,這樣定做出來的“物件”仍然是一個(gè)模板,因?yàn)槲覀冎惶鼗艘徊糠帜0鍏?shù).說明:剛才,我們?yōu)镃Student類定做的CDList模板類,其實(shí)我們沒有必要將整個(gè)CDList<CStudent>類都寫一遍,只需要重寫Add函數(shù)即可,例如:Template&
21、lt;>CDList<CStudent>:Add(CStudent& n)當(dāng)然,這樣的代碼,需要寫在Cpp文件中,并在.h文件中聲明。三、 模板程序的組織當(dāng)然,如果你足夠細(xì)心,你一定會(huì)好奇,為什么我給的例子中,模板的代碼都寫在頭文件中(.h文件),這里我們就討論模板代碼的組織方式。C+支持兩種模板代碼的組織方式,分別是包含方式(我們使用的就是包含方式)和分離方式。這兩種組織方式?jīng)]有太根本的區(qū)別,就是一個(gè)將代碼全寫在頭文件中,分離方式是像寫類一樣聲明和定義分別寫在頭文件(.h文件)和實(shí)現(xiàn)文件(cpp文件)中。下面我們分別討論下這兩種代碼組織方式。1、 包含方式本專題中,
22、所有的實(shí)例代碼中的模板代碼都是以包含方式組織的。因?yàn)楹枚嗟木幾g器(如VC6的cl)并不支持分離方式組織代碼,將代碼寫在頭文件也只是方便編譯器的預(yù)處理工作能方便的將.h文件中的代碼根據(jù)模板實(shí)參的類型生成相應(yīng)的模板類。當(dāng)然,將代碼都寫在頭文件中還有一點(diǎn)點(diǎn)小要求:A、 如果模板的成員函數(shù)寫在類外,則需要寫成如下樣式(見Exp04):template <typename T>/ 每個(gè)類外成員函數(shù)前都要有這句Node<T>* CDList<T>:AddTail( T Data )Node<T>* pNewNode = new Node<T>(D
23、ata);if ( m_pTail )m_pTail->m_pNext = pNewNode;pNewNode->m_pPrev = m_pTail;if ( m_pTail = NULL )m_pHead = pNewNode;m_pTail = pNewNode;m_nCount+;return pNewNode;B、 對(duì)于特化的代碼則需要在.h文件中聲明并在.cpp文件中定義,如果都寫在.h文件中編譯會(huì)報(bào)重定義錯(cuò)誤。2、 分離方式上面已經(jīng)提到過,所謂的分離方式組織代碼,就是將模板的聲明和定義分別寫在頭文件(.h文件)和實(shí)現(xiàn)文件(cpp文件)中,需要注意的是,并不是所有的編譯器都支持這種寫法,目前我只知道GCC支持這種寫法。當(dāng)然,分離方式組織代碼也有個(gè)小要求,就是在模板的聲明和定義的template關(guān)鍵字前都加上export關(guān)鍵字。比如:/ .h 頭文件中export template <typename T>class CDListpublic:CDList();virtual CDList();public:bool Change(int nIndex1,int nIndex2);void Release();/增加Node<T>* Ad
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年環(huán)保材料貼牌生產(chǎn)與技術(shù)支持合同
- 2025年度木工企業(yè)員工績(jī)效考核與激勵(lì)合同4篇
- 二零二五年度水利樞紐工程塊石供應(yīng)合同模板下載3篇
- 二零二五年度商業(yè)用途二房東房屋租賃經(jīng)營合同2篇
- 2025年度挖掘機(jī)械買賣與環(huán)保節(jié)能合同3篇
- 二零二五年度智能農(nóng)業(yè)無人機(jī)農(nóng)藥噴灑服務(wù)合同3篇
- 二零二四年度醫(yī)療器械研發(fā)合作與專利授權(quán)合同
- 二零二五年度農(nóng)業(yè)大棚租賃與農(nóng)業(yè)保險(xiǎn)合作合同范本4篇
- 二零二五年度牛肝菌產(chǎn)品包裝設(shè)計(jì)與印刷合同3篇
- 二零二五年度醫(yī)療設(shè)備配件更換與健康管理合同4篇
- 2025年山西國際能源集團(tuán)限公司所屬企業(yè)招聘43人高頻重點(diǎn)提升(共500題)附帶答案詳解
- 二零二五年倉儲(chǔ)配送中心物業(yè)管理與優(yōu)化升級(jí)合同3篇
- 2025屆廈門高三1月質(zhì)檢期末聯(lián)考數(shù)學(xué)答案
- 音樂作品錄制許可
- 江蘇省無錫市2023-2024學(xué)年高三上學(xué)期期終教學(xué)質(zhì)量調(diào)研測(cè)試語文試題(解析版)
- 拉薩市2025屆高三第一次聯(lián)考(一模)英語試卷(含答案解析)
- 開題報(bào)告:AIGC背景下大學(xué)英語教學(xué)設(shè)計(jì)重構(gòu)研究
- 師德標(biāo)兵先進(jìn)事跡材料師德標(biāo)兵個(gè)人主要事跡
- 連鎖商務(wù)酒店述職報(bào)告
- 2024年山東省煙臺(tái)市初中學(xué)業(yè)水平考試地理試卷含答案
- 《實(shí)踐論》(原文)毛澤東
評(píng)論
0/150
提交評(píng)論