C++程序設(shè)計(jì) 第二版 楊長(zhǎng)興 第九章_第1頁(yè)
C++程序設(shè)計(jì) 第二版 楊長(zhǎng)興 第九章_第2頁(yè)
C++程序設(shè)計(jì) 第二版 楊長(zhǎng)興 第九章_第3頁(yè)
C++程序設(shè)計(jì) 第二版 楊長(zhǎng)興 第九章_第4頁(yè)
C++程序設(shè)計(jì) 第二版 楊長(zhǎng)興 第九章_第5頁(yè)
已閱讀5頁(yè),還剩26頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第9章多態(tài)性和虛函數(shù)9.1多態(tài)性的概念多態(tài)性是指不同類的對(duì)象對(duì)于同一消息的處理具有不同的實(shí)現(xiàn)。多態(tài)性在C++中表現(xiàn)為同一形式的函數(shù)調(diào)用,可能調(diào)用不同的函數(shù)實(shí)現(xiàn)。從系統(tǒng)實(shí)現(xiàn)的角度看,C++的多態(tài)性分為兩類,一類稱為編譯時(shí)刻多態(tài)性,另一類稱為運(yùn)行時(shí)刻多態(tài)性,也稱動(dòng)態(tài)多態(tài)性。9.1.1編譯時(shí)刻的多態(tài)性C++編譯時(shí)多態(tài)性通過重載(函數(shù)重載和運(yùn)算符重載)來實(shí)現(xiàn)【例9.1】編譯時(shí)刻的多態(tài)性——運(yùn)算符重載:下面這段程序建立Rectangle類和Cuboid類,并重載運(yùn)算符“+=”,使之能用于相應(yīng)類對(duì)象的運(yùn)算。#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) //重載運(yùn)算符+={width+=rec_add.width;length+=rec_add.length;return*this; //返回當(dāng)前對(duì)象

}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//定義長(zhǎng)方體類{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)前對(duì)象

}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);}//求長(zhǎng)方體的表面積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類的重載運(yùn)算符:+=

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類的重載運(yùn)算符:+=

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運(yùn)行時(shí)刻的多態(tài)性

運(yùn)行時(shí)刻多態(tài)性的實(shí)現(xiàn)是指在程序運(yùn)行過程中根據(jù)具體情況來確定調(diào)用的是哪一個(gè)函數(shù),它是通過動(dòng)態(tài)聯(lián)編機(jī)制實(shí)現(xiàn)的【例9.2】運(yùn)行時(shí)刻的多態(tài)性運(yùn)行時(shí)的多態(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; //用基類指針指向派生類對(duì)象

cout<<"cub3'sareais(*r)"<<r->area()<<endl;

cout<<"cub3'sareais(cub3)"<<cub3.area()<<endl;return0;}程序的運(yùn)行結(jié)果如下:cub3=(1,2,3)cub3'sareais(*r)2cub3'sareais(cub3)22運(yùn)行時(shí)刻的多態(tài)性是面向?qū)ο蟮囊粋€(gè)非常重要的特征,再來看一個(gè)在結(jié)構(gòu)化編程中的例子:【例9.3】下面這段程序是利用多分支結(jié)構(gòu)編程模擬實(shí)現(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;}這種編程方式使得程序的可維護(hù)性和可擴(kuò)充性都變得很差。那么有沒有更好的方法實(shí)現(xiàn)上述例子?看看下面的程序段:voiddraw(void*f){

(*f)();}9.2虛函數(shù)虛函數(shù)的作用 虛函數(shù)從表現(xiàn)形式看是指那些被virtual關(guān)鍵字修飾的成員函數(shù)。類的一個(gè)成員函數(shù)如果被說明為虛函數(shù),表明它目前的具體實(shí)現(xiàn)僅是一種適用于當(dāng)前類的實(shí)現(xiàn),而在該類的繼承層次鏈條中有可能重新定義這個(gè)成員函數(shù)的實(shí)現(xiàn),即這個(gè)虛函數(shù)可能會(huì)被派生類的同名函數(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指向派生類對(duì)象r1f->draw();//調(diào)用r1的成員函數(shù)draw()f=&t1;//基類指針f指向派生類對(duì)象t1f->draw();//調(diào)用t1的成員函數(shù)draw()return0;}程序運(yùn)行結(jié)果:虛函數(shù)的使用虛函數(shù)的實(shí)現(xiàn)機(jī)制和調(diào)用方式與非虛函數(shù)不同,虛函數(shù)的使用需要注意以下幾點(diǎn):1.虛函數(shù)的聲明 只能將類的成員函數(shù)聲明為虛函數(shù),而不能將類外的普通函數(shù)聲明為虛函數(shù)。虛函數(shù)的作用是允許在派生類中對(duì)基類的虛函數(shù)重新定義,因而它只能用于類的繼承層次結(jié)構(gòu)中。2.虛函數(shù)的訪問權(quán)限 派生類中虛函數(shù)的訪問權(quán)限并不影響虛函數(shù)的動(dòng)態(tài)聯(lián)編,如下面的例9.5,其中派生類CDerived中重新定義了虛函數(shù)F4(),在程序的運(yùn)行中由于虛函數(shù)的機(jī)制,在CBase::F3()中調(diào)用F4()時(shí)會(huì)調(diào)用CDerived::F4(),而該函數(shù)的訪問權(quán)限是私有的。3.成員函數(shù)中調(diào)用虛函數(shù) 在類的成員函數(shù)中可以直接調(diào)用相應(yīng)類中定義或重新定義的虛函數(shù),分析這類函數(shù)的調(diào)用次序時(shí)要注意成員函數(shù)的調(diào)用一般是隱式調(diào)用,應(yīng)該將其看成是通過this指針的顯式調(diào)用?!纠?.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;程序運(yùn)行結(jié)果:

pB=&Obj;

pB->F1();Obj.F1();return0;}9.3純虛函數(shù)與抽象類純虛函數(shù)在程序設(shè)計(jì)中,通常會(huì)在類層次的頂層以虛函數(shù)的形式給出該類層次所提供的某些操作的統(tǒng)一接口,由于層次較高,有些操作無法(也無必要)給出具體的實(shí)現(xiàn),對(duì)于這種情況可以不對(duì)虛函數(shù)的實(shí)現(xiàn)進(jìn)行定義,而將它們說明為純虛函數(shù)。純虛函數(shù)是在聲明虛函數(shù)時(shí)被“初始化”為0的函數(shù)。聲明純虛函數(shù)的一般形式是:virtual<函數(shù)類型><函數(shù)名>(參數(shù)表列)=0;抽象類具有純虛函數(shù)的類無法用于創(chuàng)建對(duì)象,因?yàn)樗募兲摵瘮?shù)無函數(shù)體,所以又把這種含有純虛函數(shù)的類稱為抽象類。抽象類的主要作用是為一個(gè)族類提供統(tǒng)一的公共接口,用戶在這個(gè)基礎(chǔ)上根據(jù)自己的需要定義出功能各異的派生類,以有效地發(fā)揮多態(tài)的特性。使用抽象類時(shí)應(yīng)注意以下問題:⑴抽象類只能用作其它類的基類,不能建立抽象類的對(duì)象。因?yàn)樗募兲摵瘮?shù)沒有定義功能。⑵抽象類不能用作參數(shù)類型、函數(shù)的返回類型或顯式轉(zhuǎn)換的類型。⑶可以聲明抽象類的指針和引用,通過它們,可以指向并訪問派生類對(duì)象,從而訪問派生類的成員。⑷如果在抽象類所派生出的新類中對(duì)基類的所有純虛函數(shù)進(jìn)行了定義,那么這些函數(shù)就被賦予了功能,可以被調(diào)用。這個(gè)派生類就不是抽象類,而是可以用來定義對(duì)象的具體類。如果在派生類中沒有對(duì)所有純虛函數(shù)進(jìn)行定義,則此派生類仍然是抽象類,不能用來定義對(duì)象。9.4抽象類的實(shí)例一個(gè)抽象類就是一個(gè)界面。類層次結(jié)構(gòu)是一種逐步遞增地建立類的方式。有些抽象類也提供了重要的功能,支持進(jìn)一步向上構(gòu)造。類層次結(jié)構(gòu)中的各個(gè)類一方面為用戶提供了有用的功能,同時(shí)也作為實(shí)現(xiàn)更高級(jí)或者更特殊的類的構(gòu)造塊。這種層次結(jié)構(gòu)對(duì)于支持以逐步求精方式進(jìn)行的程序設(shè)計(jì)是非常理想的?!纠?.10】抽象類實(shí)例#include<iostream>usingnamespacestd;classCShape{//定義為一個(gè)抽象類,即一個(gè)圖形界面接口public:virtualdoublearea()const{return0.0;}//定義為虛函數(shù),允許后面覆蓋

virtualvoidprintShapeName()const=0;//定義為純虛函數(shù),由派生類負(fù)責(zé)實(shí)現(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ù)的實(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對(duì)象并初始化

CCirclecircle(4.5,14,8);//定義circle對(duì)象并初始化

CRectanglerectangle(12,3.5,8,9);//定義rectangle對(duì)象并初始化

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等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論