C++多態(tài)性與虛函數(shù)_第1頁
C++多態(tài)性與虛函數(shù)_第2頁
C++多態(tài)性與虛函數(shù)_第3頁
C++多態(tài)性與虛函數(shù)_第4頁
C++多態(tài)性與虛函數(shù)_第5頁
已閱讀5頁,還剩85頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第9章多態(tài)性與虛函數(shù)

多態(tài)性〔Polymorphism〕是面向?qū)ο蟪绦蛟O(shè)計(jì)的主要特征之一。多態(tài)性對于軟件功能的擴(kuò)展和軟件重用都有重要的作用。是學(xué)習(xí)面向?qū)ο蟪绦蛟O(shè)計(jì)必須要掌握的主要內(nèi)容之一。第十一章多態(tài)性9.1多態(tài)性的概念

9.2繼承中的靜態(tài)聯(lián)編

9.3虛函數(shù)和運(yùn)行時(shí)的多態(tài)

9.4純虛函數(shù)和抽象類

***9.5模板9.1多態(tài)性的概念

面向?qū)ο蟪绦蛟O(shè)計(jì)中多態(tài)的表現(xiàn)

多態(tài)性是指同樣的消息被不同類型的對象接收時(shí)導(dǎo)致完全不同的行為消息——指示要調(diào)用類的某個(gè)成員函數(shù)行為——成員函數(shù)執(zhí)行的結(jié)果被視為對象的行為TruepolymorphismChoiceofwhichfunctiontoexecuteismadeduringruntimeC++usesvirtualfunctions多態(tài)性——例#include<iostream>usingnamespacestd;classStudent{public:floatTuition(){//計(jì)算學(xué)費(fèi)cout<<“student”<<endl;return2500.0;}};classGraduate:publicStudent{public:

floatTuition(){cout<<“Graduate”<<endl;return8000.0}};voidmain(){Students;Graduategs;s.Tuition();//s的學(xué)費(fèi)

gs.Tuition();//gs的學(xué)費(fèi)}不同類的對象調(diào)用不同的成員函數(shù)面向?qū)ο蟪绦蛟O(shè)計(jì)中多態(tài)的表現(xiàn)面向?qū)ο蟪绦蛟O(shè)計(jì)中多態(tài)性表現(xiàn)為以下幾種形式:重載多態(tài):通過調(diào)用相同名字的函數(shù),表現(xiàn)出不同的行為。運(yùn)算符重載也是一種重載多態(tài)。運(yùn)行多態(tài):通過基類的指針,調(diào)用不同派生類的同名函數(shù)(虛函數(shù)),表現(xiàn)出不同的行為。許多面向?qū)ο蟪绦蛟O(shè)計(jì)的書籍中所說的多態(tài)性,就是這種多態(tài)。模板多態(tài):也稱為參數(shù)多態(tài),通過一個(gè)模板,得到不同的函數(shù)或不同的類。這些函數(shù)或者類具有不同的特性和不同的行為。9.1.2多態(tài)的實(shí)現(xiàn):聯(lián)編

一個(gè)具有多態(tài)性的程序語句,在執(zhí)行的時(shí)候,必須確定究竟是調(diào)用哪一個(gè)函數(shù)確定具有多態(tài)性的語句究竟調(diào)用哪個(gè)函數(shù)的過程稱為聯(lián)編〔Binding〕,有的資料也翻譯成“關(guān)聯(lián)”或者“綁定”9.1.2多態(tài)的實(shí)現(xiàn):聯(lián)編聯(lián)編有兩種方式:靜態(tài)聯(lián)編動(dòng)態(tài)聯(lián)編9.1.2靜態(tài)聯(lián)編在源程序編譯的時(shí)候就能確定具有多態(tài)性的語句調(diào)用哪個(gè)函數(shù),稱為靜態(tài)聯(lián)編。對重載函數(shù)的調(diào)用就是在編譯的時(shí)候確定具體調(diào)用哪個(gè)函數(shù),所以是屬于靜態(tài)聯(lián)編。9.1.2動(dòng)態(tài)聯(lián)編動(dòng)態(tài)聯(lián)編那么是在程序運(yùn)行時(shí),才能夠確定具有多態(tài)性的語句究竟調(diào)用哪個(gè)函數(shù)。用動(dòng)態(tài)聯(lián)編實(shí)現(xiàn)的多態(tài),也稱為運(yùn)行時(shí)的多態(tài)虛函數(shù)是支持運(yùn)行時(shí)多態(tài)的根底9.2繼承中的靜態(tài)聯(lián)編

9.2繼承中的靜態(tài)聯(lián)編通過派生類對象調(diào)用同名成員函數(shù)通過基類指針調(diào)用同名成員函數(shù)1.通過派生類對象調(diào)用同名成員函數(shù)

在派生類中可以定義和基類的成員函數(shù)同名的成員函數(shù)。這是對基類進(jìn)行改造,是派生類增加新的行為的一種常用的方法在程序編譯的時(shí)候,就可以確定派生類對象具體調(diào)用哪個(gè)同名的成員函數(shù)。這是通過靜態(tài)聯(lián)編實(shí)現(xiàn)的多態(tài)

例9.1定義Circle類和Rectangle類為Shape類的派生類,通過Circle類和Rectangle類的對象調(diào)用重載函數(shù)getArea()顯示對象的面積。

#ifndefSHAPE_H#defineSHAPE_HclassShape{public:doublegetArea();voidprint();};

classCircle:publicShape{ public:Circle(int=0,int=0,double=0.0);doublegetArea();//返回面積voidprint();private:intx,y;//圓心doubleradius;//半徑};

classRectangle:publicShape{ public: Rectangle(int=0,int=0);

doublegetArea();//面積

voidprint();private: inta,b;//長和寬};#endif

//例9.1:shape.cpp#include<iostream>usingnamespacestd;#include"shape.h" doubleShape::getArea(){cout<<"基類的getArea函數(shù),面積是";return0.0;} voidShape::print(){ cout<<"BaseclassObject"<<endl;}

Circle::Circle(intxValue,intyValue,doubleradiusValue){ x=xValue;y=yValue; radius=radiusValue;} doubleCircle::getArea(){cout<<"Circle類的getArea函數(shù),面積是";

return3.14159*radius*radius;} voidCircle::print(){cout<<"centeris";cout<<"x="<<x<<"y="<<y;cout<<";radiusis"<<radius<<endl;}

Rectangle::Rectangle(intaValue,intbValue){ a=aValue;b=bValue;} doubleRectangle::getArea(){cout<<"Rectangle類的getArea函數(shù),面積是";

returna*b;} voidRectangle::print(){cout<<"hightis"<<a;cout<<"widthis"<<b<<endl;}

//例9.1:9_1.cpp#include<iostream>usingnamespacestd;#include"shape.h"voidmain(){Circlec(22,8,3.5);Rectangler(10,10);

cout<<"調(diào)用的是";cout<<c.getArea()<<endl; //靜態(tài)聯(lián)編

cout<<"調(diào)用的是";cout<<r.getArea()<<endl;//靜態(tài)聯(lián)編} 調(diào)用的是Circle類的getarea函數(shù),面積是38.4845

調(diào)用的是Ractangle類的getarea函數(shù),面積是100

通過派生類對象調(diào)用同名成員函數(shù)通過派生類對象調(diào)用同名成員函數(shù),可以有以下的結(jié)論:派生類對象可以直接調(diào)用本類中與基類成員函數(shù)同名的函數(shù),不存在二義性;在編譯時(shí)就能確定通過對象將調(diào)用哪個(gè)函數(shù),屬于靜態(tài)聯(lián)編。Number

aNum;DerNumber

aDerNum;aNum.Prime()aDerNum.Prime();2.通過基類指針調(diào)用同名成員函數(shù)

從繼承的角度來看,派生類對象是基類對象的一個(gè)具體的特例?;蛘哒f,派生類對象是某一種特定類型的基類對象例如,Circle類是Shape類的公有繼承,“圓”是“圖形”的一種特例?;蛘哒f,圓是一種特定的圖形,具有圖形的根本特征。2.通過基類指針調(diào)用同名成員函數(shù)在關(guān)于基類對象和派生類對象的操作上,可以允許以下的操作:可以用派生類對象給基類對象賦值;

例:Circlec(22,8,3.5);Rectangler(10,10);Shapea=c;Shapeb=r;2.通過基類指針調(diào)用同名成員函數(shù)可以用派生類對象初始化基類的引用例Shape&sp=c;

可以用派生類對象的地址給基類指針賦值例:Shape*pc=&r;通過該指針,可以訪問基類的公有成員。2.通過基類指針調(diào)用同名成員函數(shù)以下這些操作是不能進(jìn)行的:不能用基類對象給派生類對象賦值;例Shapesp;

Circler=sp;不能用基類對象的地址初始化派生類對象的指針;

例Shapesp;Circle*pc=&sp;基類對象不能初始化派生類的引用;例Shapesp;Circle&pc=sp;

例9.2在例9.1所定義的類的根底上,觀察通過派生類對象地址初始化的基類對象的指針訪問getArea函數(shù)的結(jié)果。#include<iostream>usingnamespacestd;#include"shape.h" voidmain(){Shape*shape_ptr; Circlecircle(22,8,3.5); Rectanglerectangle(10,10); shape_ptr=&circle;//Circle類對象地址初始化基類指針cout<<"circle對象初始化shape_ptr指針訪問的getArea函數(shù)是"<<endl;cout<<shape_ptr->getArea()<<endl;//靜態(tài)聯(lián)編

shape_ptr=&rectangle;//Rectangle類對象地址初始化基類指針cout<<"rectangle對象初始化shape_ptr指針訪問的getArea函數(shù)是"<<endl;cout<<shape_ptr->getArea()<<endl;//靜態(tài)聯(lián)編} circle對象初始化shape_ptr指針訪問的getArea函數(shù)是基類的getArea函數(shù),面積是0rectangle對象初始化shape_ptr指針訪問的getArea函數(shù)是基類的getArea函數(shù),面積是0通過基類指針調(diào)用同名函數(shù)的說明

程序運(yùn)行結(jié)果說明:確實(shí)可以用派生類對象的地址初始化基類對象的指針;通過用派生類對象地址初始化的基類對象指針,只能調(diào)用基類的公有成員函數(shù)。在以上例子中,就是調(diào)用基類的getArea函數(shù),而不是派生類的getArea函數(shù);這種調(diào)用關(guān)系確實(shí)定,也是在編譯的過程中完成的,屬于靜態(tài)聯(lián)編。9.3虛函數(shù)和運(yùn)行時(shí)的多態(tài)9.3虛函數(shù)和運(yùn)行時(shí)的多態(tài)虛函數(shù)能夠?qū)崿F(xiàn)運(yùn)行時(shí)的多態(tài)9.3.1虛函數(shù)在類的定義中聲明虛函數(shù),格式如下:virtual返回值類型函數(shù)名(參數(shù)表);在函數(shù)原型中聲明函數(shù)是虛函數(shù)后,具體定義這個(gè)函數(shù)時(shí)就不需要再說明它是虛函數(shù)了

在基類定義中直接定義虛函數(shù)的格式是:virtual返回值類型函數(shù)名(參數(shù)表){//函數(shù)體}

9.3.1虛函數(shù)基類中的同名函數(shù)聲明或定義為虛函數(shù)后,派生類的同名函數(shù)無論是不是用virtual來說明,都將自動(dòng)地成為虛函數(shù)從程序可讀性考慮,一般都會(huì)在這些函數(shù)的聲明或定義時(shí),用virtual來加以說明

例9.3將例9.2進(jìn)行修改,使得程序具有運(yùn)行時(shí)的多態(tài)的效果。

//例9.3:shape1.h#ifndefSHAPE_H#defineSHAPE_HclassShape{ public:

virtualdoublegetArea(); voidprint(); };

classCircle:publicShape{ public: Circle(int=0,int=0,double=0.0);

virtualdoublegetArea();

voidprint();private: intx,y;

doubleradius; };

classRectangle:publicShape{ public: Rectangle(int=0,int=0);

virtual

doublegetArea();

voidprint();private: inta,b;};#endif//例9.3:shape1.cpp#include<iostream>usingnamespacestd;#include"shape1.h" doubleShape::getArea(){cout<<"基類的getArea函數(shù),面積是";return0.0;}voidShape::print(){ cout<<"BaseclassObject"<<endl;}

Circle::Circle(intxValue,intyValue,doubleradiusValue){ x=xValue;y=yValue; radius=radiusValue;} doubleCircle::getArea(){cout<<"Circle類的getArea函數(shù),面積是";

return3.14159*radius*radius;} voidCircle::print(){cout<<"centeris";cout<<"x="<<x<<"y="<<y;cout<<";radiusis"<<radius<<endl;} Rectangle::Rectangle(intaValue,intbValue){a=aValue;b=bValue;} doubleRectangle::getArea(){cout<<"Rectangle類的getArea函數(shù),面積是";

returna*b;} voidRectangle::print(){cout<<"hightis"<<a;cout<<"widthis"<<b<<endl;}

//例9.3:9_3.cpp#include<iostream>usingnamespacestd;#include"shape1.h" voidmain(){Shape*shape_ptr;

Circlecircle(22,8,3.5);Rectanglerectangle(10,10);shape_ptr=&circle; cout<<“circle對象初始化shape_ptr指針訪問的getArea函數(shù)是”<<endl;cout<<shape_ptr->getArea()<<endl;//動(dòng)態(tài)聯(lián)編

shape_ptr=&rectangle;

cout<<"rectangle對象初始化shape_ptr指針訪問的getArea函數(shù)是"<<endl;cout<<shape_ptr->getArea()<<endl;//動(dòng)態(tài)聯(lián)編}

circle對象初始化shape_ptr指針訪問的getArea函數(shù)是Circle類的getArea函數(shù),面積是38.4845rectangle對象初始化shape_ptr指針訪問的getArea函數(shù)是Rectangle類的getArea函數(shù),面積是100動(dòng)態(tài)聯(lián)編:一種運(yùn)行時(shí)決定的多態(tài)性9.3.1虛函數(shù)要實(shí)現(xiàn)運(yùn)行時(shí)的多態(tài),需要以下條件:通過指向基類對象的指針訪問和基類成員函數(shù)同名的派生類成員函數(shù);shape_ptr=&circle; shape_ptr->getArea();

或者用派生類對象初始化的基類對象的引用訪問和基類成員函數(shù)同名的派生類成員函數(shù);shape&sp=circle; sp.getArea();

派生類的繼承方式必須是公有繼承;基類中的同名成員函數(shù)必須定義為虛函數(shù)。

9.3.2虛函數(shù)的使用虛函數(shù)必須正確的定義和使用。否那么,即使在函數(shù)原型前加了virtual的說明,也可能得不到運(yùn)行時(shí)多態(tài)的特性。必須首先在基類中聲明虛函數(shù)。在多級繼承的情況下,也可以不在最高層的基類中聲明虛函數(shù)。例如:在第二層定義的虛函數(shù),可以和第三層的虛函數(shù)形成動(dòng)態(tài)聯(lián)編。9.3.2虛函數(shù)的使用基類和派生類的同名函數(shù),必須函數(shù)名、返回值、參數(shù)表全部相同,才能作為虛函數(shù)來使用。否那么,即使函數(shù)用virtual來說明,也不具有虛函數(shù)的行為;靜態(tài)成員函數(shù)不可以聲明為虛函數(shù)。構(gòu)造函數(shù)也不可以聲明為虛函數(shù);析構(gòu)函數(shù)可以聲明為虛函數(shù),即可以定義虛析構(gòu)函數(shù)。

例9.4分析以下程序,編譯時(shí)哪個(gè)語句會(huì)出現(xiàn)錯(cuò)誤?為什么?將有錯(cuò)誤的語句屏蔽掉以后,程序運(yùn)行結(jié)果如何?其中哪些調(diào)用是靜態(tài)聯(lián)編,哪些是動(dòng)態(tài)聯(lián)編?

#include<iostream.h>classB{public:virtualvoidvf1(){cout<<"B::vf1被調(diào)用\n";}virtual

voidvf2(){cout<<"B::vf2被調(diào)用\n";}voidf(){cout<<"B::f被調(diào)用\n";}};classD:publicB{public:virtualvoidvf1(){cout<<"D::vf1被調(diào)用\n";}voidvf2(inti){cout<<i<<endl;}voidf(){cout<<“D::f\n被調(diào)用”;}};

voidmain(){Dd;B*bp=&d;bp->vf1();bp->vf2();bp->vf2(10);}將這個(gè)語句注釋掉后,運(yùn)行結(jié)果將顯示:

D::vf1被調(diào)用B::vf2被調(diào)用函數(shù)調(diào)用bp->vf2(10);是錯(cuò)誤的。因?yàn)榕缮惖膙f2函數(shù)和基類的vf2函數(shù)的參數(shù)不同,派生類的vf2就不是虛函數(shù)。

其中bp->vf1()調(diào)用是動(dòng)態(tài)聯(lián)編。bp->vf2()是靜態(tài)聯(lián)編。9.3.3虛析構(gòu)函數(shù)如果用動(dòng)態(tài)創(chuàng)立的派生類對象的地址初始化基類的指針,創(chuàng)立的過程不會(huì)有問題:仍然是先調(diào)用基類構(gòu)造函數(shù),再執(zhí)行派生類構(gòu)造函數(shù)但是,在用delete運(yùn)算符刪除這個(gè)指針的時(shí)候,由于指針是指向基類的,通過靜態(tài)聯(lián)編,只會(huì)調(diào)用基類的析構(gòu)函數(shù),釋放基類成員所占用的空間。而派生類成員所占用的空間將不會(huì)被釋放

#include<iostream>usingnamespacestd;classShape {public:Shape(){cout<<"Shape類構(gòu)造函數(shù)被調(diào)用\n";}~Shape(){cout<<"Shape類析構(gòu)函數(shù)被調(diào)用\n";}; }; classCircle:publicShape {public:Circle(intxx=0,intyy=0,doublerr=0.0){x=xx;y=yy;radius=rr;cout<<"Circle類構(gòu)造函數(shù)被調(diào)用\n";}~Circle(){cout<<"Circle類析構(gòu)函數(shù)被調(diào)用\n";}private:intx,y; doubleradius; }; voidmain(){Shape*shape_ptr;shape_ptr=newCircle(3,4,5);deleteshape_ptr;}定義簡單的Shape類和Circle類,觀察基類指針的創(chuàng)立和釋放時(shí)如何調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)程序運(yùn)行后在屏幕上顯示:Shape類構(gòu)造函數(shù)被調(diào)用Circle類構(gòu)造函數(shù)被調(diào)用Shape類析構(gòu)函數(shù)被調(diào)用9.3.3虛析構(gòu)函數(shù)為了解決派生類對象釋放不徹底的問題,必須將基類的析構(gòu)函數(shù)定義為虛析構(gòu)函數(shù)。格式:

virtual

Shape();

此后,無論派生類析構(gòu)函數(shù)是不是用virtual來說明,也都是虛析構(gòu)函數(shù)。再用deleteshape_ptr來釋放基類指針時(shí),就會(huì)通過動(dòng)態(tài)聯(lián)編調(diào)用派生類的析構(gòu)函數(shù)。9.4純虛函數(shù)和抽象類9.4純虛函數(shù)和抽象類前例,基類Shape并不是一個(gè)具體的“形狀”的抽象,而是各種實(shí)際的“形狀”的抽象在C++中,對于那些在基類中不需要定義具體的行為的函數(shù),可以定義為純虛函數(shù)

對于那些只是反映一類事物公共特性的類,在C++中可以定義為“抽象類”

9.4純虛函數(shù)和抽象類純虛函數(shù)的聲明格式:

virtual返回值類型函數(shù)名(參數(shù)表)=0;9.4純虛函數(shù)和抽象類純虛函數(shù)的聲明和使用有以下的特點(diǎn):純虛函數(shù)一定是在基類中聲明的;在多級繼承的情況下,純虛函數(shù)除了在最高層基類中聲明外,也可以在較低層的基類中聲明;純虛函數(shù)是沒有函數(shù)體的。函數(shù)體是用“=0”來代替了;純虛函數(shù)是不可以被調(diào)用的。但凡需要被調(diào)用的函數(shù)都不可以聲明為純虛函數(shù)。9.4純虛函數(shù)和抽象類包含純虛函數(shù)的類為抽象類

抽象類定義的一般形式是:class類名{public:

virtual

返回值類型函數(shù)名(參數(shù)表)=0;//其他函數(shù)的聲明;};9.4純虛函數(shù)和抽象類抽象類的定義和使用具有以下的特點(diǎn):

不可以定義抽象類的對象;可以定義抽象類的指針和抽象類的引用。目的是通過這些指針或引用訪問派生類的虛函數(shù),實(shí)現(xiàn)運(yùn)行時(shí)的多態(tài);如果抽象類的派生類中沒有具體實(shí)現(xiàn)純虛函數(shù)的功能,這樣的派生類仍然是抽象類;抽象類中除了純虛函數(shù)外,還可以定義其他的非純虛函數(shù)。

例9.6編寫一個(gè)程序,可以創(chuàng)立Circle類或者Rectangle類的對象,并且顯示所創(chuàng)立對象的面積。在編程中注意使用多態(tài)性。

//例9.6:shape2.hclassShape{ //基類Shape的定義public:

virtualdoublegetArea()=0;//純虛函數(shù)

voidprint();

virtual~Shape(){} //虛析構(gòu)函數(shù)};

classCircle:publicShape{public: Circle(int=0,int=0,double=0.0); doublegetArea();//返回面積

voidprint();//輸出Circle類對象tprivate: intx,y; //圓心座標(biāo)

doubleradius;//圓半徑};

classRectangle:publicShape{ public: Rectangle(int=0,int=0); //構(gòu)造函數(shù)

doublegetArea();//返回面積

voidprint();//輸出Rectangle類對象private: inta,b;//矩形的長和寬};

//例9.6:shape2.cpp#include<iostream>usingnamespacestd;#include"shape2.h"

voidShape::print(){ cout<<"BaseclassObject"<<endl;} Circle::Circle(intxValue,intyValue,doubleradiusValue){x=xValue;y=yValue;radius=radiusValue;}

doubleCircle::getArea(){cout<<"Circle類的getArea函數(shù),面積是";

return3.14159*radius*radius;} voidCircle::print(){cout<<"centeris";cout<<"x="<<x<<"y="<<y;cout<<";radiusis"<<radius<<endl;}

Rectangle::Rectangle(intaValue,intbValue){ a=aValue;b=bValue;} doubleRectangle::getArea(){cout<<"Rectangle類的getArea函數(shù),面積是";

returna*b;} voidRectangle::print(){cout<<"hightis"<<a;cout<<"widthis"<<b<<endl;}

//例9.6:9_6.cpp#include<iostream>usingnamespacestd;#include"shape2.h" voidmain(){Circlec(1,2,3);Rectangler(1,2);Shape*shape_ptr;shape_ptr=&c;//指針指向circle類對象cout<<shape_ptr->getArea()<<endl;//動(dòng)態(tài)聯(lián)編shape_ptr=&r;//指針指向rectangle類對象cout<<shape_ptr->getArea()<<endl;//動(dòng)態(tài)聯(lián)編

} Circle類的getArea函數(shù),面積是28.27Rectangle類的getArea函數(shù),面積是2說明這個(gè)程序中,使用了本章所介紹的虛函數(shù)、純虛函數(shù)、虛析構(gòu)函數(shù)、基類指針訪問派生類對象等技術(shù),實(shí)現(xiàn)了運(yùn)行時(shí)的多態(tài);程序具有很好的可擴(kuò)展性。如果需要增加新的派生類,當(dāng)然要增加和派生類定義有關(guān)的代碼,和創(chuàng)立對象所需要的語句;抽象類中可以為各派生類定義一些通用的接口。這些通用的接口就是抽象類中的純虛函數(shù)。新增加的派生類的對象,都可以使用這樣的通用接口,表現(xiàn)派生類對象的行為特性。9.5模板9.5模板函數(shù)重載

intmax(intx,inty);floatmax(floatx,floaty);模板是C++中的通用程序模塊。在這些程序模塊中有一些數(shù)據(jù)類型是不具體的,或者說是抽象的。當(dāng)這些抽象的數(shù)據(jù)類型更換為不同的具體數(shù)據(jù)類型以后,就會(huì)產(chǎn)生一系列具體的程序模塊

template<typenameT>Tmax(Tx,Ty);考慮只寫一個(gè)函數(shù)如何?9.5模板C++中的模板包括函數(shù)模板類模板函數(shù)模板實(shí)例化后產(chǎn)生的函數(shù),稱為模板函數(shù)類模板實(shí)例化后產(chǎn)生的類,稱為模板類

9.5.1函數(shù)模板函數(shù)模板定義的根本格式:template<typename參數(shù)化類型名>函數(shù)返回類型函數(shù)名(形式參數(shù)列表){函數(shù)體}“template”是定義模板的關(guān)鍵字;在一對尖括號(hào)<>內(nèi),關(guān)鍵字“typename”后面聲明所使用的“參數(shù)化類型名”;關(guān)鍵字“typename”可以用“class”取代。9.5.1函數(shù)模板模板的其余局部和一般的函數(shù)定義的格式完全相同。只是在函數(shù)定義時(shí)可以使用參數(shù)化類型來代表各種具體的數(shù)據(jù)類型。參數(shù)化類型可以用于:函數(shù)返回值類型;函數(shù)形式參數(shù)的類型;函數(shù)體內(nèi),自動(dòng)變量的類型。

例9.9函數(shù)模板的定義和使用:定義和使用確定3個(gè)數(shù)據(jù)的最大值函數(shù)模板。#include<iostream>usingnamespacestd;template<typenameT>Tmax_value(Tx,Ty,Tz)//函數(shù)模板的定義:求x、y、z的最大值{Ttemp; temp=x>y?x:y; returntemp>z?temp:z;}voidmain(){cout<<max_value(12,32,21)<<endl;//用整數(shù)作實(shí)參調(diào)用函數(shù)模板cout<<max_value('a','A','9')<<endl;//用字符作實(shí)參調(diào)用函數(shù)模板}程序執(zhí)行后,輸出: 32

a

例9.10編寫一個(gè)帶有兩個(gè)形式參數(shù)的函數(shù)模板,可以按指定的操作數(shù)類型相乘。

#include<iostream>

template<typenameP1,typenameP2>P1cal(P1x,P2y)//有兩個(gè)參數(shù)化類型名:P1和P2{return(x*(P1)y);}//按x類型進(jìn)行乘法voidmain(){intw=2;floatz=1.5;cout<<cal(w,z)<<endl;//按整型數(shù)相乘

cout<<cal(z,w)<<endl;//按浮點(diǎn)數(shù)相乘}程序運(yùn)行的結(jié)果是:23.0帶有確定類型的參數(shù)的函數(shù)模板例:template<classQ1>

voidArrayInput(Q1array,intnum){//輸入數(shù)組元素//……

}函數(shù)模板的形式參數(shù)表中除了使用參數(shù)化類型名以外,還可以使用確定類型的參數(shù)。也就是說,函數(shù)模板的參數(shù)表中,一定要包含參數(shù)化類型名,但不一定都使用參數(shù)化類型名。還可以根據(jù)需要,使用確定類型的參數(shù)。

例9.11設(shè)計(jì)和編寫一個(gè)通用的輸入數(shù)組元素的函數(shù)模板。可以用它來輸入各種不同數(shù)據(jù)類型的數(shù)組。

#include<iostream.h>#include<typeinfo.h>template<classQ1> //函數(shù)模板

voidArrayInput(Q1array,intnum){cout<<"輸入"<<num<<"個(gè)"<<typeid(Q1).name()<<'\b'<<"型數(shù)據(jù)"<<endl;for(unsignedj=0;j<num;j++)//輸入數(shù)組元素 cin>>array[j]; }typeid運(yùn)算符,它可以在程序運(yùn)行時(shí),顯示指定的數(shù)據(jù)的類型voidmain(){intnumber; floatfloatArray[4];intintArray[3]; number=sizeof(floatArray)/sizeof(float);ArrayInput(floatArray,number);//輸入整型數(shù)組元素

number=sizeof(intArray)/sizeof(int);ArrayInput(intArray,number);//輸入浮點(diǎn)型數(shù)組元素}9.5.2函數(shù)模板使用中的問題

用戶定義的類取代參數(shù)化類型:在這種情況下,函數(shù)模板實(shí)例化后,在函數(shù)的表達(dá)式中參與運(yùn)算的就是類的對象。對象可以直接使用的運(yùn)算符只有賦值運(yùn)算符“=”。如果表達(dá)式中需要對象進(jìn)行其他的運(yùn)算,就必須在相應(yīng)的類的定義中,對于要使用的運(yùn)算符進(jìn)行重載。例如,在例9.9中,函數(shù)模板是求3個(gè)實(shí)參的最大值,需要使用運(yùn)算符“>”。如果要用對象來作實(shí)參,相應(yīng)的類中要對“>”運(yùn)算符進(jìn)行重載。

例9.12用例9.9的函數(shù)模板,求3個(gè)Circle類對象的最大值。

#include<iostream> template<typenameT>Tmax_value(Tx,Ty,Tz)//函數(shù)模板的定義

{Ttemp; if(x>y)temp=x; elsetemp=y; if(z>temp)temp=z; returntemp;}

classCircle {private: intx,y; //圓心座標(biāo)

doubleradius; //圓半徑public:Circle(inta=0,intb=0,doublec=0.0) {x=a;y=b;radius=c;}friendostream&operator<<(ostream&,Circle&);//重載“<<”運(yùn)算符 intoperator>(Circlem2)//重載“>”運(yùn)算符

{if(radius>m2.radius) return1; elsereturn0; }};

ostream&operator<<(ostream&out,Circle&C1){out<<"x="<<C1.x<<"y="<<C1.y;out<<"radius="<<C1.radius;returnout;}voidmain(){CircleC1(2,3,5),C2(3,5,8),C3(3,2,6);//定義3個(gè)Circle類對象

cout<<max_value(12,32,21)<<endl;//用整數(shù)作實(shí)參

cout<<max_value(‘a(chǎn)’,‘A’,‘9’)<<endl;//用字符作實(shí)參cout<<max_value(C1,C2,C3)<<endl;//用對象作參數(shù)}程序運(yùn)行結(jié)果是:32ax=3y=5radius=8

9.5.2函數(shù)模板使用中的問題函數(shù)模板不支持參數(shù)自動(dòng)轉(zhuǎn)換

對于例9.9的函數(shù)模板:

template<typenameT> Tmax_value(Tx,Ty,Tz);如果用以下的方式來調(diào)用: cout<<max_value(12,3.2,21)<<endl;在編譯時(shí)會(huì)出現(xiàn)編譯錯(cuò)誤:“templateparameter'T'isambiguous”要解決這樣的問題,就需要函數(shù)模板和一般的函數(shù)聯(lián)合使用。即需要函數(shù)模板和一般的函數(shù)的重載

9.5.3重載函數(shù)模板重載函數(shù)模板可以是函數(shù)模板和另一個(gè)參數(shù)數(shù)目不同的函數(shù)模板的重載,也可以是函數(shù)模板和非模板函數(shù)的重載。一般所說的函數(shù)模板重載是指后一種情況。函數(shù)模板和非模板函數(shù)重載,可以解決函數(shù)模板不支持參數(shù)自動(dòng)轉(zhuǎn)換的問題;當(dāng)所使用的參數(shù)類型〔不是類類型〕不支持函數(shù)模板中某些操作時(shí),就需要為這樣的參數(shù)專門編寫相應(yīng)的非模板函數(shù)。和已經(jīng)定義的函數(shù)模板形成重載的關(guān)系。9.5.3重載函數(shù)模板例如,需要用例9.9的函數(shù)模板來比較3個(gè)結(jié)構(gòu)體變量,返回其中的最大值。由于結(jié)構(gòu)體變量不支持直接的比較操作“>”。要實(shí)現(xiàn)這樣的功能,就要再寫一個(gè)函數(shù)。假定結(jié)構(gòu)體的定義是: structcourse {char*name; floatscore; };9.5.3重載函數(shù)模板三個(gè)結(jié)構(gòu)體變量的比較函數(shù)如下:coursemax_value(courses1,courses2,courses3){courses4;if(s1.score>s2.score)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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ǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論