版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第9章多態(tài)性和虛函數(shù)9.1多態(tài)性的概念多態(tài)性是指不同類的對象對于同一消息的處理具有不同的實現(xiàn)。多態(tài)性在C++中表現(xiàn)為同一形式的函數(shù)調(diào)用,可能調(diào)用不同的函數(shù)實現(xiàn)。從系統(tǒng)實現(xiàn)的角度看,C++的多態(tài)性分為兩類,一類稱為編譯時刻多態(tài)性,另一類稱為運行時刻多態(tài)性,也稱動態(tài)多態(tài)性。9.1.1編譯時刻的多態(tài)性C++編譯時多態(tài)性通過重載(函數(shù)重載和運算符重載)來實現(xiàn)【例9.1】編譯時刻的多態(tài)性——運算符重載:下面這段程序建立Rectangle類和Cuboid類,并重載運算符“+=”,使之能用于相應(yīng)類對象的運算。#include<iostream>usingnamespacestd;classRectangle//定義矩形類{public:
Rectangle(doublew=0,doublel=0); //缺省構(gòu)造函數(shù)
voidset_wl(double
w,doublel);doubleget_w()const;doubleget_l()const;doublearea();~Rectangle(){}; //析構(gòu)函數(shù)
Rectangle&operator+=(Rectangle&rec_add) //重載運算符+={width+=rec_add.width;length+=rec_add.length;return*this; //返回當(dāng)前對象
}protected:
intwidth;
intlength;};Rectangle::Rectangle(doublew,doublel):width(w),length(l){}voidRectangle::set_wl(double
w,doublel){width=w;length=l;}doubleRectangle::get_w()const{returnwidth;}doubleRectangle::get_l()const{returnlength;}doubleRectangle::area(){returnwidth*length;}classCuboid:publicRectangle//定義長方體類{public:
Cuboid(doublew=0,doublel=0,doubleh=0);voidset_wlh(double
w,double
l,doubleh);doubleget_h()const;doublearea();
Cuboid&operator+=(Cuboid&cub_add){width+=cub_add.width;length+=cub_add.length;height+=cub_add.height;return*this; //返回當(dāng)前對象
}protected:doubleheight;};Cuboid::Cuboid(double
w,double
l,double
h):Rectangle(w,l),height(h){}voidCuboid::set_wlh(double
w,double
l,doubleh){width=w;length=l;height=h;}doubleCuboid::get_h()const{returnheight;}doubleCuboid::area(){return2*(width*length+width*height+length*height);}//求長方體的表面積intmain(){Rectanglerec1(1,2);Rectanglerec2;
Cuboidcub1(1,2,3);
Cuboidcub2;rec2.set_wl(2,4);cub2.set_wlh(5,10,15);
cout<<"rec1:(width="<<rec1.get_w()<<",length="<<rec1.get_l()<<")"<<endl;
cout<<"rec2:(width="<<rec2.get_w()<<",length="<<rec2.get_l()<<")"<<endl;
rec2+=rec1; //調(diào)用Rectangle類的重載運算符:+=
cout<<"rec2.width=("<<rec2.get_w()<<",length="<<rec2.get_l()<<")"<<endl;
cout<<"cub1:(width="<<cub1.get_w()<<",length="<<cub1.get_l()<<",height=";
cout<<cub1.get_h()<<")"<<endl;
cout<<"cub2:(width="<<cub2.get_w()<<",length="<<cub2.get_l()<<",height=";
cout<<cub2.get_h()<<")"<<endl;cub2+=cub1; //調(diào)用Cuboid類的重載運算符:+=
cout<<"cub2:(width="<<cub2.get_w()<<",length="<<cub2.get_l()<<",height=";
cout<<cub2.get_h()<<")"<<endl;
cout<<"rec2'sareais"<<rec2.area()<<endl;
cout<<"cub2'sareais"<<cub2.area()<<endl;return0;}9.1.2運行時刻的多態(tài)性
運行時刻多態(tài)性的實現(xiàn)是指在程序運行過程中根據(jù)具體情況來確定調(diào)用的是哪一個函數(shù),它是通過動態(tài)聯(lián)編機制實現(xiàn)的【例9.2】運行時刻的多態(tài)性運行時的多態(tài)性。仍然用例9.1中定義的Rectangle類和Cuboid類。//*************ex9_2.cpp*************//此處加上例9.1中定義的Rectangle類和Cuboid類。intmain(){Rectangle*r;
Cuboidcub3(1,2,3);
cout<<"cub3=("<<cub3.get_w()<<","<<cub3.get_l()<<",";
cout<<cub3.get_h()<<")"<<endl;r=&cub3; //用基類指針指向派生類對象
cout<<"cub3'sareais(*r)"<<r->area()<<endl;
cout<<"cub3'sareais(cub3)"<<cub3.area()<<endl;return0;}程序的運行結(jié)果如下:cub3=(1,2,3)cub3'sareais(*r)2cub3'sareais(cub3)22運行時刻的多態(tài)性是面向?qū)ο蟮囊粋€非常重要的特征,再來看一個在結(jié)構(gòu)化編程中的例子:【例9.3】下面這段程序是利用多分支結(jié)構(gòu)編程模擬實現(xiàn)繪制圖形的函數(shù)。//********ex9_3.cpp*********voiddraw(int
obj_figure){switch(obj_figure)
case0://rectangle
draw_rectangle();
//cout<<”drawrectangle”<<endl;
break;
case1://triangle
draw_triangle();
//cout<<”drawtriangle”<<endl;
break;
case2://circle
draw_circle();
//cout<<"draw_circle"<<endl;
break;}這種編程方式使得程序的可維護性和可擴充性都變得很差。那么有沒有更好的方法實現(xiàn)上述例子?看看下面的程序段:voiddraw(void*f){
(*f)();}9.2虛函數(shù)虛函數(shù)的作用 虛函數(shù)從表現(xiàn)形式看是指那些被virtual關(guān)鍵字修飾的成員函數(shù)。類的一個成員函數(shù)如果被說明為虛函數(shù),表明它目前的具體實現(xiàn)僅是一種適用于當(dāng)前類的實現(xiàn),而在該類的繼承層次鏈條中有可能重新定義這個成員函數(shù)的實現(xiàn),即這個虛函數(shù)可能會被派生類的同名函數(shù)所覆蓋(override)。例:使用虛函數(shù)的例子#include<iostream>usingstd::cout;usingstd::endl;classfigure{public:virtualvoiddraw()//將draw()定義為虛函數(shù){cout<<"drawfigure"<<endl;}};classrectangle:publicfigure{voiddraw(){
cout<<"drawrectangle"<<endl;}};classtriangle:publicfigure{voiddraw(){
cout<<"drawtriangle"<<endl;}};intmain(){figure*f;rectangler1;trianglet1;f=&r1;//基類指針f指向派生類對象r1f->draw();//調(diào)用r1的成員函數(shù)draw()f=&t1;//基類指針f指向派生類對象t1f->draw();//調(diào)用t1的成員函數(shù)draw()return0;}程序運行結(jié)果:虛函數(shù)的使用虛函數(shù)的實現(xiàn)機制和調(diào)用方式與非虛函數(shù)不同,虛函數(shù)的使用需要注意以下幾點:1.虛函數(shù)的聲明 只能將類的成員函數(shù)聲明為虛函數(shù),而不能將類外的普通函數(shù)聲明為虛函數(shù)。虛函數(shù)的作用是允許在派生類中對基類的虛函數(shù)重新定義,因而它只能用于類的繼承層次結(jié)構(gòu)中。2.虛函數(shù)的訪問權(quán)限 派生類中虛函數(shù)的訪問權(quán)限并不影響虛函數(shù)的動態(tài)聯(lián)編,如下面的例9.5,其中派生類CDerived中重新定義了虛函數(shù)F4(),在程序的運行中由于虛函數(shù)的機制,在CBase::F3()中調(diào)用F4()時會調(diào)用CDerived::F4(),而該函數(shù)的訪問權(quán)限是私有的。3.成員函數(shù)中調(diào)用虛函數(shù) 在類的成員函數(shù)中可以直接調(diào)用相應(yīng)類中定義或重新定義的虛函數(shù),分析這類函數(shù)的調(diào)用次序時要注意成員函數(shù)的調(diào)用一般是隱式調(diào)用,應(yīng)該將其看成是通過this指針的顯式調(diào)用。【例9.5】在成員函數(shù)中調(diào)用虛函數(shù)//*********ex9_5.cpp***********#include<iostream>usingnamespacestd;classCBase{public:voidF1(){
cout<<"=>CBase-F1=>";F2();}voidF2(){
cout<<"CBase-F2=>";F3();}virtualvoidF3(){
cout<<"CBase-F3=>";F4();//即this->F4()}virtualvoidF4(){
cout<<"CBase-F4=>";}};classCDerived:public
CBase{private:virtualvoidF4(){
cout<<"Derived-F4=>out"<<endl;}public:voidF1(){
cout<<"=>Derived-F1=>";CBase::F2();}voidF2(){
cout<<"=>Derived-F2=>";F3();//即this->F3()}};intmain(){
CBase*pB;
CDerived
Obj;程序運行結(jié)果:
pB=&Obj;
pB->F1();Obj.F1();return0;}9.3純虛函數(shù)與抽象類純虛函數(shù)在程序設(shè)計中,通常會在類層次的頂層以虛函數(shù)的形式給出該類層次所提供的某些操作的統(tǒng)一接口,由于層次較高,有些操作無法(也無必要)給出具體的實現(xiàn),對于這種情況可以不對虛函數(shù)的實現(xiàn)進行定義,而將它們說明為純虛函數(shù)。純虛函數(shù)是在聲明虛函數(shù)時被“初始化”為0的函數(shù)。聲明純虛函數(shù)的一般形式是:virtual<函數(shù)類型><函數(shù)名>(參數(shù)表列)=0;抽象類具有純虛函數(shù)的類無法用于創(chuàng)建對象,因為它的純虛函數(shù)無函數(shù)體,所以又把這種含有純虛函數(shù)的類稱為抽象類。抽象類的主要作用是為一個族類提供統(tǒng)一的公共接口,用戶在這個基礎(chǔ)上根據(jù)自己的需要定義出功能各異的派生類,以有效地發(fā)揮多態(tài)的特性。使用抽象類時應(yīng)注意以下問題:⑴抽象類只能用作其它類的基類,不能建立抽象類的對象。因為它的純虛函數(shù)沒有定義功能。⑵抽象類不能用作參數(shù)類型、函數(shù)的返回類型或顯式轉(zhuǎn)換的類型。⑶可以聲明抽象類的指針和引用,通過它們,可以指向并訪問派生類對象,從而訪問派生類的成員。⑷如果在抽象類所派生出的新類中對基類的所有純虛函數(shù)進行了定義,那么這些函數(shù)就被賦予了功能,可以被調(diào)用。這個派生類就不是抽象類,而是可以用來定義對象的具體類。如果在派生類中沒有對所有純虛函數(shù)進行定義,則此派生類仍然是抽象類,不能用來定義對象。9.4抽象類的實例一個抽象類就是一個界面。類層次結(jié)構(gòu)是一種逐步遞增地建立類的方式。有些抽象類也提供了重要的功能,支持進一步向上構(gòu)造。類層次結(jié)構(gòu)中的各個類一方面為用戶提供了有用的功能,同時也作為實現(xiàn)更高級或者更特殊的類的構(gòu)造塊。這種層次結(jié)構(gòu)對于支持以逐步求精方式進行的程序設(shè)計是非常理想的。【例9.10】抽象類實例#include<iostream>usingnamespacestd;classCShape{//定義為一個抽象類,即一個圖形界面接口public:virtualdoublearea()const{return0.0;}//定義為虛函數(shù),允許后面覆蓋
virtualvoidprintShapeName()const=0;//定義為純虛函數(shù),由派生類負(fù)責(zé)實現(xiàn)
virtualvoiddraw()const=0;//定義為純虛函數(shù)};classCPoint:public
CShape//公有繼承CShape{public:
CPoint(int=0,int=0);//聲明構(gòu)造函數(shù)
voidsetPoint(int,int);
int
getX()const{returnx;}
int
getY()const{returny;}virtualvoidprintShapeName()const//覆蓋CShape基類的純虛函數(shù)
{cout<<"Point:";}virtualvoiddraw()const;private:
int
x,y;};CPoint::CPoint(int
a,intb)//CPoint構(gòu)造函數(shù)的實現(xiàn){setPoint(a,b);}voidCPoint::setPoint(int
a,intb){x=a;y=b;}voidCPoint::draw()const{cout<<"["<<x<<","<<y<<"]";}classCCircle:public
CPoint{public:
CCircle(doubler=0.0,intx=0,inty=0);voidsetRadius(double);doublegetRadius()const;virtualdoublearea()const;virtualvoidprintShapeName()const{cout<<"Circle:";}virtualvoiddraw()const;private:doubleradius;};CCircle::CCircle(double
r,int
a,int
b):CPoint(a,b){setRadius(r);}voidCCircle::setRadius(doubler){radius=r>0?r:0;}doubleCCircle::getRadius()const{returnradius;}doubleCCircle::area()const{return3.1415926*radius*radius;}voidCCircle::draw()const{
CPoint::draw();
cout<<";Radius="<<radius;}classCRectangle:public
CPoint{public:
CRectangle(doublewidth=0.0,doubleheight=0.0,intx=0,inty=0);voidsetWidth(double);doublegetWidth();voidsetHeight(double);doublegetHeight();virtualdoublearea()const;virtualvoidprintShapeName()const{cout<<"Rectangle:";}virtualvoiddraw()const;private:doublewidth;doubleheight;};CRectangle::CRectangle(double
w,double
h,intx,inty):CPoint(x,y){setWidth(w);
setHeight(h);}voidCRectangle::setWidth(doublew){width=w>0?w:0;}voidCRectangle::setHeight(doubleh){height=h>0?h:0;}doubleCRectangle::getWidth(){returnwidth;}doubleCRectangle::getHeight(){returnheight;}doubleCRectangle::area()const{returnwidth*height;}voidCRectangle::draw()const{CPoint::draw();
cout<<"width="<<width<<";Height="<<height;}voidViaPointer(const
CShape*);voidViaReference(const
CShape&);intmain(){
CPointpoint(5,9);//定義point對象并初始化
CCirclecircle(4.5,14,8);//定義circle對象并初始化
CRectanglerectangle(12,3.5,8,9);//定義rectangle對象并初始化
point.printShapeName();//靜態(tài)綁定
point.draw();//靜態(tài)綁定
cout<<endl;
circle.printShapeName();//靜態(tài)綁定
circle.draw();//靜態(tài)綁定
cout<<endl;
rectangle.printShapeName(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 游樂園可持續(xù)發(fā)展策略考核試卷
- 2024年出版發(fā)行合同(教育教材)
- 2024年醫(yī)療行業(yè)市場調(diào)研合同
- 2024年全球貿(mào)易指南:進出口合同中英對照
- 2024年東莞市企業(yè)兼并與收購合同
- 2024年合作伙伴意向:銷售合同模板
- 2024年全球化視野下的知識產(chǎn)權(quán)聯(lián)盟合同
- 2024年可再生能源發(fā)電項目合作共建合同
- (2024版)分期付款服務(wù)合同范本-市場營銷策劃
- 機械施工企業(yè)勞務(wù)分包合同實例
- 欠錢不還訴狀書范文2024年
- 液化氣站雙重預(yù)防體系手冊
- 2024年村官面試試題及答案
- 2023年中級經(jīng)濟師《人力資源管理》真題及答案解析(11月12日上午)
- 2024中科信工程咨詢(北京)限責(zé)任公司招聘6人高頻考題難、易錯點模擬試題(共500題)附帶答案詳解
- 教師資格考試小學(xué)心理健康面試2024年下半年自測試題及答案解析
- Module10Theweather教學(xué)設(shè)計2024-2025學(xué)年外研版英語八年級上冊
- 親子溝通與孩子心理健康
- DL∕ T 736-2010 農(nóng)村電網(wǎng)剩余電流動作保護器安裝運行規(guī)程
- 2024-2025學(xué)年度北師版七上數(shù)學(xué)-第十周自主評價練習(xí)(期中測評)【課件】
- 消費積分返利合同范本
評論
0/150
提交評論