面向對象程序設計輔導材料-1_第1頁
面向對象程序設計輔導材料-1_第2頁
面向對象程序設計輔導材料-1_第3頁
面向對象程序設計輔導材料-1_第4頁
面向對象程序設計輔導材料-1_第5頁
已閱讀5頁,還剩44頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第12章模板(Template)面向對象程序設計(C++)12.1引言12.1引言:IntStack創(chuàng)建一個棧,這個棧類只存放int類型的值1.支持初始化、push()、pop()、清除等方法;2.棧中所有元素的類型都是int.VP用來存放int的棧類IntStackclassIntStack{int*v;//棧底int*p;//棧頂intsz;//棧的大小public:IntStack(ints){v=p=newint[sz=s];}~IntStack(){delete[]v;}voidpush(inta){*p++=a};intpop(){return*--p;}intsize()const{returnp-v;}};12.2代碼重用12.2如何實現(xiàn)代碼重用?VPVPCharStackObjStack

現(xiàn)在希望再創(chuàng)建能存放其他類型的棧類,如:char,float,甚至用戶自定義的類型對象。

從棧的結構和操作方式上來說,除了每個元素的類型不一樣外,其它沒有任何區(qū)別。因此應該可以重用IntStack的代碼。問題是:如何重用?12.2.1C的方法之一:代碼拷貝classCharStack{

char*v;//棧底char*p;//棧頂intsz;//棧的大小public:CharStack(ints){v=p=newchar[sz=s];}~CharStack(){delete[]v;}voidpush(chara){*p++=a};

charpop(){return*--p;}intsize()const{returnp-v;}};缺點:1.表現(xiàn)繁瑣;2.易發(fā)生錯誤;3.缺乏美感;非常低效!12.2.2C的方法之二:typedeftypedefintT;classStack{

T*v;//棧底

T*p;//棧頂intsz;//棧的大小public:Stack(ints){v=p=newT[sz=s];}~Stack(){delete[]v;}voidpush(Ta){*p++=a};

Tpop(){return*--p;}intsize()const{returnp-v;}};缺點:1.每次使用Stack之前,都必須加上typedef語句,很麻煩。2.由于T是全局名,無法重新定義,一個類不能同時用到char棧和int棧;12.2.3smalltak方法(略)使用繼承復雜,混亂!12.2.4C++的方法:模板改進typedef,將它從預處理器移入到編譯器中。新的代碼替換裝置稱為“模板”(template)。非常象宏,卻更清晰,更易于使用;模板實際上是一組類;形式上很簡潔。12.3模板語法12.3.1類模板定義template<classT>class類模板名{//類模板的定義};注:T是一個類模板的類型參數(shù),可以有一個或多個,可以是任意類型。template<classT>

classStack{

T*v;//棧底

T*p;//棧頂intsz;//棧的大小public:Stack(ints){v=p=newT[sz=s];}~Stack(){delete[]v;}voidpush(Ta){*p++=a};

Tpop(){return*--p;}intsize()const{returnp-v;}};例:Stack<T>12.3.2類模板實例化給類模板的參數(shù)指定具體的類型,這一過程稱為

“類模板的實例化”。類模板名<具體類型表>

Stack<int>;//實例化成int型棧類;Stack<char>;//實例化成char型棧類;注意:類模板實例化后的結果是類,而不是對象!12.3.3類對象生成類模板實例化得到的類可以進行實例化,生成最終的對象。Stack<int>si(20);//創(chuàng)建一個大小為20的整形棧;Stack<char>si(40);//創(chuàng)建一個字符型棧;Stackstack(100);//error,未指定模板參數(shù),

類模板與類的實例化Stack<T>Stack<int>Stack<char>…………Stack<int>sint(10)Stack<int>si2(20)……模板實例化類實例化完整的stack<T>程序:template<classT>classStack{

T*v;//棧底

T*p;//棧頂intsz;//棧的大小public:Stack(ints){v=p=newT[sz=s];}~Stack(){delete[]v;}voidpush(Ta){*p++=a};

Tpop(){return*--p;}intsize()const{returnp-v;}};voidmain(){inti;Stack<char>sch(20);

Stack<char>sch2(20);

Stack<int>sint(10);for(i=0;i<10;i++){sint.push(i+1);}for(i=0;i<20;i++){sch.push(‘*’);}//….for(i=10;i>0;i--){if(sint.pop()!=i){error();}}for(i=0;i<20;i++){if(sch.pop()!=‘*’){error();}}}一個值得注意的問題!12.3.4非內聯(lián)函數(shù)定義12.3.4.1語法template<classT>返回值類型類模板名<類模板參數(shù)>::成員函數(shù)名(函數(shù)參數(shù)1,函數(shù)參數(shù)2,函數(shù)參數(shù)3)非內聯(lián)函數(shù)定義的Stack<T>template<classT>classStack{T*v;//棧底T*p;//棧頂intsz;//棧的大小public:Stack(ints;~Stack();voidpush(Ta);Tpop();intsize();};template<classT>Stack<T>::Stack(ints){v=p=newT[sz=s];}template<classT>Stack<T>::~Stack(){delete[]v;}

template<classT>voidStack<T>::push(Ta){*p++=a};template<classT>TStack<T>::pop(){return*--p;}template<classT>intStack<T>::size()const{returnp-v;}};12.3.4.2關于頭文件對類來說,在創(chuàng)建非內聯(lián)函數(shù)定義時,我們通常把定義放在.h文件中,而把實現(xiàn)放在.cpp中。

(實際上是所謂的頭文件原則:“在頭文件中,不要放置分配存儲空間的任何東西”,為了防止在連接期間的多重定義錯誤。)對模板來說,即使是在創(chuàng)建非內聯(lián)函數(shù)定義時,模板的所有定義和實現(xiàn)都必須放入一個頭文件中。

why?

因為模板很特殊,在template<…>之后的任何東西都意味著編譯器在當時不為它分配存儲空間(即不編譯成目標代碼),而是一直處于等待狀態(tài)直到一個模板示例被告知。如果沒有被實例化,模板不會被編譯成目標代碼:template<classT>classStack{

T*v;//棧底

T*p;//棧頂intsz;//棧的大小public:Stack(ints;~Stack();voidpush(Ta);

Tpop();intsize();};文件:Stack.htemplate<classT>Stack<T>::Stack(ints){v=p=newT[sz=s];}template<classT>Stack<T>::~Stack(){delete[]v;}template<classT>voidStack<T>::push(Ta){*p++=a};

template<classT>

TStack<T>::pop(){return*--p;}

template<classT>intStack<T>::size()const{returnp-v;}};文件:Stack.cpp#include“Stack.h”voidmain(){Stack<int>si(10);si.push(1);//連接錯誤}文件:test.cpperrorLNK2001:unresolvedexternalsymbol"public:int__thiscallStack<int>::push(int)"(?push@?$stack@H@@QAEHXZ)發(fā)生連接錯誤:FromMSDN:LinkerToolsErrorLNK2001unresolvedexternalsymbol"symbol"Codewillgeneratethiserrormessageifitreferencessomething(likeafunction,variable,orlabel)thatthelinkercan’tfindinallthelibrariesandobjectfilesitsearches.Ingeneral,therearetworeasonsthiserroroccurs:whatthecodeasksfordoesn’texist(thesymbolisspelledincorrectlyorusesthewrongcase,forexample),orthecodeasksforthewrongthing(youareusingmixedversionsofthelibraries?somefromoneversionoftheproduct,othersfromanotherversion).NumerouskindsofcodingandbuilderrorscancauseLNK2001.Severalspecificcausesarelistedbelow,andsomehavelinkstomoredetailedexplanations.……12.3.5模板中的常量模板參數(shù)并不局限于類定義的類型,可以使用編譯器內置類型。

tempate<classT,intsize=100>classArray{…;}類型參數(shù)內置類型參數(shù)參數(shù)的默認值例:模板中的常量#include"../require.h"#include<iostream>usingnamespacestd;template<classT,intsize=100>classArray{Tarray[size];//在實例化時,設置Array類的長度public:T&operator[](intindex){//重載[]實現(xiàn)關聯(lián)數(shù)組

require(index>=0&&index<size,"Indexoutofrange");returnarray[index];}intlength()const{returnsize;}};classNumber{floatf;public:Number(floatff=0.0f):f(ff){}Number&operator=(constNumber&n){//重載賦值符f=n.f;return*this;}operatorfloat()const{returnf;}

friendostream&operator<<(ostream&os,constNumber&x){returnos<<x.f;}};template<classT,intsize=20>classHolder{Array<T,size>*np;public:Holder():np(0){}T&operator[](inti){require(0<=i&&i<size);if(!np)np=newArray<T,size>;returnnp->operator[](i);}intlength()const{returnsize;}~Holder(){deletenp;}};intmain(){Holder<Number>h;

for(inti=0;i<20;i++)h[i]=i;

for(intj=0;j<20;j++)cout<<h[j]<<endl;}///:~12.4模板的派生12.4.1從類派生模板模板實際上是一組類,如果某一類定義了這一組類的公共屬性,則模板可以從該類派生。classBase{inti;protected:floatf;public:voidg(){cout<<“g”<endl;}};template<classT>classderived:publicBase{Tt;//…};voidmain(){derived<int>di;derived<char>dc;di.g();//dc.g();}12.4.2從類模板派生模板template<classT>classBase{inti;protected:Tf;public:voidg(){cout<<“g”<endl;}};類模板的基類如果也是模板,派生類模板的參數(shù)表應包含基類模板的參數(shù)。template<classT1,classT2>classderived:publicBase<T2>{T1t;//…};voidmain(){derived<int,char>di;derived<char,float>dc;di.g();//dc.g();}12.4.2從類模板派生模板(續(xù))如果派生類沒有類型參數(shù),或者說它的類型參數(shù)與基類的類型參數(shù)相同時,派生類地模板參數(shù)只要包含基類的模板參數(shù)就可以了template<classT>classC:publicBase<T>//模板C的參數(shù)與基類相同{Tc;//…};12.5函數(shù)模板實際上是定義了一組函數(shù)12.5.1函數(shù)模板的定義template<模板參數(shù)表>返回值類型函數(shù)名(函數(shù)參數(shù)表){//函數(shù)模板的定義}例1:求兩個對象間的最大值template<classT>Tmax(Ta,Tb){returna>b?a:b;}這里T可以是int,char,float,或者任何重載了>算符的對象。例2:關于模板參數(shù)template<classT>voidf(){//error,函數(shù)參數(shù)列表中無函數(shù)模板參數(shù)TTa;//…}12.5.2函數(shù)模板的實例化函數(shù)模板的實例化不需要用戶顯式進行,而是在函數(shù)調用時由編譯器來處理。voidmain(){inta,b;charc,d;intm1=max(a,b);//調用max(inta,intb);charm2=max(c,d);//調用max(charc,chard);}

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論