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

下載本文檔

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

文檔簡介

第9章多態性和虛函數9.1多態性的概念多態性是指不同類的對象對于同一消息的處理具有不同的實現。多態性在C++中表現為同一形式的函數調用,可能調用不同的函數實現。從系統實現的角度看,C++的多態性分為兩類,一類稱為編譯時刻多態性,另一類稱為運行時刻多態性,也稱動態多態性。9.1.1編譯時刻的多態性C++編譯時多態性通過重載(函數重載和運算符重載)來實現【例9.1】編譯時刻的多態性——運算符重載:下面這段程序建立Rectangle類和Cuboid類,并重載運算符“+=”,使之能用于相應類對象的運算。#include<iostream>usingnamespacestd;classRectangle//定義矩形類{public:

Rectangle(doublew=0,doublel=0); //缺省構造函數

voidset_wl(double

w,doublel);doubleget_w()const;doubleget_l()const;doublearea();~Rectangle(){}; //析構函數

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; //調用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; //調用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運行時刻的多態性

運行時刻多態性的實現是指在程序運行過程中根據具體情況來確定調用的是哪一個函數,它是通過動態聯編機制實現的【例9.2】運行時刻的多態性運行時的多態性。仍然用例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;}程序的運行結果如下:cub3=(1,2,3)cub3'sareais(*r)2cub3'sareais(cub3)22運行時刻的多態性是面向對象的一個非常重要的特征,再來看一個在結構化編程中的例子:【例9.3】下面這段程序是利用多分支結構編程模擬實現繪制圖形的函數。//********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;}這種編程方式使得程序的可維護性和可擴充性都變得很差。那么有沒有更好的方法實現上述例子?看看下面的程序段:voiddraw(void*f){

(*f)();}9.2虛函數虛函數的作用 虛函數從表現形式看是指那些被virtual關鍵字修飾的成員函數。類的一個成員函數如果被說明為虛函數,表明它目前的具體實現僅是一種適用于當前類的實現,而在該類的繼承層次鏈條中有可能重新定義這個成員函數的實現,即這個虛函數可能會被派生類的同名函數所覆蓋(override)。例:使用虛函數的例子#include<iostream>usingstd::cout;usingstd::endl;classfigure{public:virtualvoiddraw()//將draw()定義為虛函數{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();//調用r1的成員函數draw()f=&t1;//基類指針f指向派生類對象t1f->draw();//調用t1的成員函數draw()return0;}程序運行結果:虛函數的使用虛函數的實現機制和調用方式與非虛函數不同,虛函數的使用需要注意以下幾點:1.虛函數的聲明 只能將類的成員函數聲明為虛函數,而不能將類外的普通函數聲明為虛函數。虛函數的作用是允許在派生類中對基類的虛函數重新定義,因而它只能用于類的繼承層次結構中。2.虛函數的訪問權限 派生類中虛函數的訪問權限并不影響虛函數的動態聯編,如下面的例9.5,其中派生類CDerived中重新定義了虛函數F4(),在程序的運行中由于虛函數的機制,在CBase::F3()中調用F4()時會調用CDerived::F4(),而該函數的訪問權限是私有的。3.成員函數中調用虛函數 在類的成員函數中可以直接調用相應類中定義或重新定義的虛函數,分析這類函數的調用次序時要注意成員函數的調用一般是隱式調用,應該將其看成是通過this指針的顯式調用?!纠?.5】在成員函數中調用虛函數//*********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;程序運行結果:

pB=&Obj;

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

virtualvoidprintShapeName()const=0;//定義為純虛函數,由派生類負責實現

virtualvoiddraw()const=0;//定義為純虛函數};classCPoint:public

CShape//公有繼承CShape{public:

CPoint(int=0,int=0);//聲明構造函數

voidsetPoint(int,int);

int

getX()const{returnx;}

int

getY()const{returny;}virtualvoidprintShapeName()const//覆蓋CShape基類的純虛函數

{cout<<"Point:";}virtualvoiddraw()const;private:

int

x,y;};CPoint::CPoint(int

a,intb)//CPoint構造函數的實現{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();//靜態綁定

point.draw();//靜態綁定

cout<<endl;

circle.printShapeName();//靜態綁定

circle.draw();//靜態綁定

cout<<endl;

rectangle.printShapeName(

溫馨提示

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

評論

0/150

提交評論