C++程序設計 第二版 楊長興 第九章_第1頁
C++程序設計 第二版 楊長興 第九章_第2頁
C++程序設計 第二版 楊長興 第九章_第3頁
C++程序設計 第二版 楊長興 第九章_第4頁
C++程序設計 第二版 楊長興 第九章_第5頁
已閱讀5頁,還剩26頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第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類,并重載運算符“+=”,使之能用于相應類對象的運算。#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; //返回當前對象

}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; //返回當前對象

}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)僅是一種適用于當前類的實現(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)用相應類中定義或重新定義的虛函數(shù),分析這類函數(shù)的調(diào)用次序時要注意成員函數(shù)的調(diào)用一般是隱式調(diào)用,應該將其看成是通過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;程序運行結(jié)果:

pB=&Obj;

pB->F1();Obj.F1();return0;}9.3純虛函數(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)一的公共接口,用戶在這個基礎上根據(jù)自己的需要定義出功能各異的派生類,以有效地發(fā)揮多態(tài)的特性。使用抽象類時應注意以下問題:⑴抽象類只能用作其它類的基類,不能建立抽象類的對象。因為它的純虛函數(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)對于支持以逐步求精方式進行的程序設計是非常理想的。【例9.10】抽象類實例#include<iostream>usingnamespacestd;classCShape{//定義為一個抽象類,即一個圖形界面接口public:virtualdoublearea()const{return0.0;}//定義為虛函數(shù),允許后面覆蓋

virtualvoidprintShapeName()const=0;//定義為純虛函數(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ù)的實現(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)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論