第6章 多態(tài)性及虛函數(shù)_第1頁(yè)
第6章 多態(tài)性及虛函數(shù)_第2頁(yè)
第6章 多態(tài)性及虛函數(shù)_第3頁(yè)
第6章 多態(tài)性及虛函數(shù)_第4頁(yè)
第6章 多態(tài)性及虛函數(shù)_第5頁(yè)
已閱讀5頁(yè),還剩122頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、第6章 多態(tài)性與虛函數(shù) 第第6章章 多態(tài)性與虛函數(shù)多態(tài)性與虛函數(shù)6.1 什么是多態(tài)性6.2 一個(gè)典型的例子6.3 利用虛函數(shù)實(shí)現(xiàn)動(dòng)態(tài)多態(tài)性 6.3.1 虛函數(shù)的作用 6.3.2 靜態(tài)關(guān)聯(lián)與動(dòng)態(tài)關(guān)聯(lián) 6.3.3在什么情況下應(yīng)當(dāng)聲明虛函數(shù) 6.3.4虛析構(gòu)函數(shù)6.4 純虛函數(shù)與抽象類 6.4.1 純虛函數(shù) 6.4.2 抽象類 6.4.3 應(yīng)用實(shí)例 第6章 多態(tài)性與虛函數(shù) 6.1 什么是多態(tài)性什么是多態(tài)性 多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計(jì)的一個(gè)重要特征。如果一種語(yǔ)言只支持類而不支持多態(tài),是不能稱為面向?qū)ο笳Z(yǔ)言的,只能說是基于對(duì)象的,如Ada,VB就屬此類。C+支持多態(tài)性。利用多態(tài)性可以設(shè)計(jì)和實(shí)現(xiàn)一個(gè)易于擴(kuò)展

2、的系統(tǒng)。 多態(tài)是指一個(gè)事物有多種形態(tài)。第6章 多態(tài)性與虛函數(shù) 6.1 什么是多態(tài)性什么是多態(tài)性 所謂多態(tài)性就是當(dāng)不同對(duì)象收到相同的消息時(shí)產(chǎn)生不同的動(dòng)作。多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計(jì)重要內(nèi)容,利用多態(tài)性,可以更好地進(jìn)行程序設(shè)計(jì),不但實(shí)現(xiàn)代碼復(fù)用, 而且使程序簡(jiǎn)潔,清楚和便于更新和升級(jí)。 多態(tài)性是通過虛函數(shù)實(shí)現(xiàn)的。 在C+中,多態(tài)性表現(xiàn)形式之一是:具有不同功能的函數(shù)可以用同一個(gè)函數(shù)名,這樣就可以用一個(gè)函數(shù)名調(diào)用不同內(nèi)容的函數(shù)。第6章 多態(tài)性與虛函數(shù) 6.1 什么是多態(tài)性什么是多態(tài)性生活中多態(tài)性的例子如下:學(xué)校的校長(zhǎng)向社會(huì)發(fā)布一則消息:9月1日新學(xué)年開學(xué)。不同的對(duì)象會(huì)做出不同的響應(yīng):學(xué)生準(zhǔn)備好課本準(zhǔn)時(shí)到

3、校上課;家長(zhǎng)籌集學(xué)費(fèi);教師要備好課;后勤部門要準(zhǔn)備好教室、宿舍和食堂.由于事先對(duì)各種人的任務(wù)已作了規(guī)定,有了預(yù)案,因此,在得到同一個(gè)消息時(shí),各種人都知道自己應(yīng)當(dāng)怎么做,這就是多態(tài)性。如果不利用多態(tài)性,校長(zhǎng)就要分別給學(xué)生、家長(zhǎng)、教師、后勤部門等不同對(duì)象分別發(fā)通知,各自要做什么。第6章 多態(tài)性與虛函數(shù) 6.1 什么是多態(tài)性什么是多態(tài)性從系統(tǒng)實(shí)現(xiàn)角度看,多態(tài)性分為:靜態(tài)多態(tài)性和動(dòng)態(tài)多態(tài)性。編譯時(shí)的多態(tài)性(靜態(tài)多態(tài)性)是通過重載函數(shù)實(shí)現(xiàn)的。重載函數(shù)有兩種方式:(1).在一個(gè)類中說明的重載在一個(gè)類中說明的重載函數(shù)之間靠所帶的參數(shù)個(gè)數(shù)或參數(shù)類型的不同加以區(qū)分。在編譯時(shí)系統(tǒng)可以根據(jù)參數(shù)的上述差異來區(qū)分這些函

4、數(shù)。(2).基類成員函數(shù)在派生類中重載在基類和派生類中的重載函數(shù)有兩種情況,一種是參數(shù)有所差別的重載,這種情況的使用和定義與上面在一個(gè)類中說明的重載函數(shù)相同。第6章 多態(tài)性與虛函數(shù) 6.1 什么是多態(tài)性什么是多態(tài)性另一種是函數(shù)所帶的參數(shù)完全相同,只是他們屬于不同的類。在編譯時(shí)要區(qū)分這種函數(shù)有兩種方式:(1)使用類名加以區(qū)分如:circle:show() 或 point:show()(2)根據(jù)對(duì)象加以區(qū)分 如:circles acircle;point apoint;acircle.show();apoint.show();第6章 多態(tài)性與虛函數(shù) 6.1 什么是多態(tài)性什么是多態(tài)性動(dòng)態(tài)多態(tài)性的特點(diǎn)

5、是:不在編譯時(shí)確定調(diào)用的是哪個(gè)函數(shù),而是在程序運(yùn)行過程中才動(dòng)態(tài)地確定操作所針對(duì)的對(duì)象。又稱為運(yùn)行時(shí)的多態(tài)性。運(yùn)行時(shí)的多態(tài)性是用虛函數(shù)來實(shí)現(xiàn)的。第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子 例6.1 先建立一個(gè)Point類,包含數(shù)據(jù)成員x,y(坐標(biāo)點(diǎn))。以它為基類,派生出一個(gè)Circle(圓)類,增加數(shù)據(jù)成員r(半徑)。再以Circle類為直接基類,派生出一個(gè)Cylinder(圓柱體)類,再增加數(shù)據(jù)成員h(高)。要求編寫程序,重載運(yùn)算符“”,使之能用于輸出以上類對(duì)象。第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子(1)聲明類Point#include /聲明類Poi

6、ntclass Pointprotected:float x,y;public:void setpoint(float,float); / 設(shè)置坐標(biāo)值float getx() const return x; /讀x坐標(biāo),getx為常成員函數(shù)float gety() const return y; /讀y坐標(biāo),gety為常成員函數(shù)friend ostream & operator(ostream &,const Point &); /友元重載運(yùn)算符;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子/下面定義Point類的成員函數(shù)/定義Point類的構(gòu)造函數(shù)Po

7、int:Point(float a,float b) /對(duì)x,y初始化 x=a;y=b;void Point:setpoint(float a,float b) /對(duì)x,y賦以新值x=a;y=b;/重載運(yùn)算符 ,使之能輸出點(diǎn)的坐標(biāo)ostream & operator(ostream &output,const Point &p) outputp.x,p.yendl; return output;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子為提高效率,對(duì)程序分步調(diào)試。下面的main函數(shù)對(duì)基類Point進(jìn)行調(diào)試。int main() Point p(3.5,

8、6.4); /建立Point類對(duì)象p,對(duì)x,y初始化 coutx=p.getx(),y=p.gety()endl; /輸出p的坐標(biāo)值x,y p.setpoint(8.5,6.8); /重新設(shè)置p的坐標(biāo)值 coutp(new):pendl; /用重載運(yùn)算符輸出p點(diǎn)坐標(biāo)運(yùn)行結(jié)果:x=3.5,y=6.4p(new):8.5,6.8第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子(2)聲明派生類Circleclass Circle:public Point /Circle是Point類的公用派生類private:float radius;public:Circle(float x=0,fl

9、oat y=0,float r=0); /構(gòu)造函數(shù)void setRadius(float); /設(shè)置半徑值的函數(shù)float getRadius() const; /讀取半徑值的函數(shù)float area() const; /計(jì)算圓面積的函數(shù)friend ostream & operator(ostream &,const Circle &); /重載運(yùn)算符;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子/定義Circle類的構(gòu)造函數(shù),對(duì)圓心坐標(biāo)和半徑初始化Circle:Circle(float a,float b,float r):Point(a,b),r

10、adius(r)/定義設(shè)置半徑值的函數(shù)void Circle:setRadius(float r) radius=r;/定義讀取半徑的函數(shù)float Circle:getRadius() const return radius;/ 定義計(jì)算圓面積的函數(shù)float Circle:area() const return 3.14159*radius*radius; / 重載運(yùn)算符,使之按規(guī)定的形式輸出圓的信息ostream & operator(ostream &output,const Circle &c) outputCenter=c.x,c.y,r=c.radius,

11、area=c.area()endl; return output;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子為了測(cè)試以上Circle類的定義,可以寫下面的主函數(shù):int main() Circle c(3.5,6.4,5.2); /建立Circle類對(duì)象c并指定圓心坐標(biāo)和半徑 coutoriginal circle:nx=c.getx(),y=c.gety(),r=c.getRadius(),area=c.area()endl; /輸出圓心坐標(biāo)、半徑和面積 c.setRadius(7.5); /設(shè)置半徑值 c.setpoint(5,5); /設(shè)置圓心坐標(biāo)值x,y coutne

12、w circle:n:c; /用重載運(yùn)算符輸出圓對(duì)象的信息 Point &pRef=c; /pRef是Point類的引用,被c初始化 coutpRef:pRef; /輸出pRef的信息 return 0;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子運(yùn)行結(jié)果:original circle: (輸出原來的圓的數(shù)據(jù))x=3.5,y=6.4,r=5.2,area=84.9486new circle: (輸出修改后的圓的數(shù)據(jù))Center=5,5,r=7.5,area=176.714pRef:5,5 (輸出圓的圓心“點(diǎn)”的數(shù)據(jù)) 第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一

13、個(gè)典型的例子(3)聲明Circle的派生類Cylinderclass Cylinder:public Circle Cylinder(float x=0,float y=0,float r=0,float h=0); /構(gòu)造函數(shù) void setHeight(float); /設(shè)置圓柱高的函數(shù) float getHeight() const; /讀取圓柱高的函數(shù) float area() const; /計(jì)算圓表面積的函數(shù) float volume() const; /計(jì)算圓柱體積的函數(shù) friend ostream& operator (ostream&, const Cyl

14、inder&); /重載運(yùn)算符 protected: float height; /圓柱高;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子/定義構(gòu)造函數(shù)Cylinder:Cylinder(float a,float b,float r,float h):Circle(a,b,r),height(h)/定義設(shè)置圓柱高的函數(shù)Cylinder:setHeight(float h)height=h;/定義讀取圓柱高的函數(shù) float Cylinder:getHeight() const return height; /定義計(jì)算圓表面積的函數(shù) float Cylinder:area

15、() const return 2*Circle:area()+2*3.14159*radius*height; / 定義計(jì)算圓柱體積的函數(shù) float Cylinder:volume() const return Circle:area()*height; / 重載運(yùn)算符的函數(shù)ostream & operator(ostream &output,const Cylinder& cy) outputCenter=cy.x,cy.y,r=cy.radius,h=cy.heightnarea=cy.area(),volume=cy.volume()endl; return

16、output;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子可以寫出下面的主函數(shù):int main() Cylinder cy1(3.5,6.4,5.2,10); /建立Cylinder類對(duì)象cy1,并初始化coutoriginal Cylinder:nx=cy1.getx(),y=cy1.gety(),r=cy1.getRadius(),h=cy1.getHeight()narea=cy1.area(),volume=cy1.volume()endl; /用系統(tǒng)定義的運(yùn)算符輸出圓柱cy1的數(shù)據(jù) cy1.setHeight(15); /設(shè)置圓柱高 cy1.setRadius(7.

17、5); /設(shè)置圓半徑 cy1.setpoint(5,5); /設(shè)置圓心坐標(biāo)值x,y coutnnew Cylinder:n:cy1; /用重載運(yùn)算符輸出cy1的數(shù)據(jù) Point &pRef=cy1; /pRef是Point類對(duì)象的引用 coutpRef as a point:pRef; /pRef作為一個(gè)點(diǎn)輸出 Circle &cRef=cy1; /cRef是Circle類對(duì)象的引用 coutncRef as a circle:cRef; /cRef作為一個(gè)圓輸出 return 0;第6章 多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子運(yùn)行結(jié)果: original cyl

18、inder: (輸出cy1的初始值) x=3.5,y=6.4,r=5.2,h=10 (輸出圓心坐標(biāo)x,y。半徑r,高h(yuǎn)) area=496.623,volume=849.486 new cylinder: (輸出cy1的新值) Center=5,5,r=7.5,h=15 (以5,5形式輸出圓心坐標(biāo)) area=1060.29,volume=2650.72 (輸出圓柱表面積area和體積volume) pRef as a point:5,5 (pRef作為一個(gè)點(diǎn)輸出) cRef as a Circle:Center=5,5,r=7.5,area=176.714 (cRef作為一個(gè)圓輸出)第6章

19、多態(tài)性與虛函數(shù) 6.2 一個(gè)典型的例子一個(gè)典型的例子程序分析:在Cylinder類中定義了area函數(shù),它與Circle類中的area函數(shù)同名,cy1.area()調(diào)用的是Cylinder類的area函數(shù),而不是Circle類的area()函數(shù),這兩個(gè)函數(shù)屬于覆蓋,不是重載。 pRef是Point類的引用,用cy1對(duì)其初始化,但它不是cy1的別名,只是cy1中基類Point部分的別名,在輸出pRef時(shí)是作為一個(gè)Point類對(duì)象輸出的,也就是說,它是一個(gè)點(diǎn)。第6章 多態(tài)性與虛函數(shù) 6.3 利用虛函數(shù)實(shí)現(xiàn)動(dòng)態(tài)多態(tài)性利用虛函數(shù)實(shí)現(xiàn)動(dòng)態(tài)多態(tài)性 6.3.1 虛函數(shù)的作用 6.3.2 靜態(tài)關(guān)聯(lián)與動(dòng)態(tài)關(guān)聯(lián)

20、6.3.3在什么情況下應(yīng)當(dāng)聲明虛函數(shù) 6.3.4虛析構(gòu)函數(shù)第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(1)一般對(duì)象的指針 指向一般對(duì)象的指針與指向一般變量的指針,其定義和使用語(yǔ)法都是相同的。#include class class1 /.public:void show()coutthis is the class1!n; class class2 /.public:void show()coutshow();ptr2-show();return 1;運(yùn)行結(jié)果為:this is class of class1! th

21、is is class of class2!第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(2)引入派生類后的對(duì)象指針前面介紹的一般對(duì)象的指針,他們各自獨(dú)立,沒有聯(lián)系,不能混用。引入派生類后,由于派生類是基類派生出來的,派生類和基類之間有關(guān),他們的指針也是相關(guān)的。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用#include #include class stringchar *name;int length;public:string(char *str) length=strlen(str);name=new charlength+1;strcpy(name,s

22、tr);void show()coutnamen; 第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 class de_string:public stringint age;public:de_string(char *str,int age):string(str)de_string:age=age;void show()string:show();coutthe age is:ageshow(); /調(diào)用string類的成員函數(shù)show()ptr1=&s2; /將ptr1指向string類的派生類de_string的對(duì)象s2ptr1-show(); /調(diào)用s2對(duì)象所屬

23、基類的show()函數(shù)ptr2=&s2; /將指針ptr2指向de_string類對(duì)象s2ptr2-show(); /調(diào)用de_string類的成員函數(shù)show()return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用運(yùn)行結(jié)果為:SmithJeanJeanthe age is:20從例子中可以看出,雖然ptr1指針已經(jīng)指向了s2對(duì)象(ptr1=&s1; ),但是它所調(diào)用的函數(shù)(ptr1-show(); )仍然是其基類對(duì)象的成員函數(shù),這是使用時(shí)要注意的問題。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 注意:(1)可以用一個(gè)聲明讓指向基類對(duì)

24、象的指針指向它的公有派生類的對(duì)象。若試圖指向它的私有派生類的對(duì)象則是被禁止的。class base;class derive:base;main()base obj1,*ptr1;derive obj2;ptr1=&obj1;ptr1=&obj2; /錯(cuò)誤,試圖指向它的私有派生類return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(2)不能將一個(gè)聲明為指向派生類對(duì)象的指針指向其基類的一個(gè)對(duì)象。class base;class derive:public base;main()base obj1;derive obj2,*ptr;ptr=&obj

25、2;ptr=&obj1; /錯(cuò)誤,試圖將派生類的 指針指向基類的指針return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(3)聲明為指向基類對(duì)象的指針,當(dāng)其指向派生類對(duì)象時(shí),只能利用他來直接訪問派生類從基類繼承來的成員,不能直接訪問公有派生類中特定的成員。class basepublic:void show1();class derive:public basepublic:void show2();第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用main()base obj1,*ptr;derive obj2;ptr=&obj1;ptr-

26、show1();ptr=&obj2;ptr-show1(); /調(diào)用obj2從其基類繼承來的show1()ptr-show2(); /錯(cuò)誤,試圖調(diào)用派生類的特定成員return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用如想訪問其公有派生類的特定成員,可以將基類指針顯式類型轉(zhuǎn)換為派生類指針來實(shí)現(xiàn)。class poinprotected:int x,y;public:point(int x,int y)point:x=x;point:y=y;void show()putpixel(x,y,getcolor();void show1()coutx=xy=yn;第6章

27、多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class circles:public pointint radius;public:circles(int x,int y,int radius):point(x,y)circles:radius=radius;void show()circle(x,y,radius);void show2()show1();coutradius=radiusshow(); /調(diào)用obj1對(duì)象所屬類point中的成員函數(shù),在屏幕上畫一個(gè)點(diǎn)ptr=&obj2;ptr-show(); /調(diào)用obj2對(duì)象從基類繼承來的成員函數(shù),在屏幕上畫一個(gè)點(diǎn)第6章

28、多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(circles*)ptr)-show(); /調(diào)用obj2對(duì)象的特定成員show(),畫一個(gè)圓getch();closegraph();ptr=&obj1;ptr-show1();ptr=&obj2;(circles*)ptr)-show2(); /調(diào)用obj2對(duì)象的成員函數(shù)show2()getch();return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用為什么要引入虛函數(shù),先看一個(gè)例子:#includeclass basepublic:void who()coutthis is the class

29、 of base! n;class derive1:public basepublic:void who()coutthis is the class of derive1! n;class derive2:public basepublic:void who()coutwho();p=&obj2;p-who(); /調(diào)用base類的who()p=&obj3;p-who(); /調(diào)用base類的who()obj2.who();obj3.who();return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用程序的運(yùn)行結(jié)果:this is the class o

30、f base! this is the class of base! this is the class of base! this is the class of derive1! this is the class of derive2! 在結(jié)果中與預(yù)想的相符, 卻是不希望得到的。也就是說,通過指針引起的普通成員函數(shù)調(diào)用,僅僅與指針的類型有關(guān),而與此刻指向什么對(duì)象無關(guān)。要采用對(duì)指針的強(qiáng)制類型轉(zhuǎn)換的方法。(derive1*)p)-who();要使對(duì)象指針具有多態(tài)性,需要引入虛函數(shù),將基類的who()函數(shù)聲明為虛函數(shù)。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用虛函數(shù)的定義:虛

31、函數(shù)是引入了派生類概念以后,用來表現(xiàn)基類和派生類的成員函數(shù)之間的一種關(guān)系的。虛函數(shù)定義是在基類中進(jìn)行的,前面加上virtual。在派生類中可重新定義此函數(shù),但函數(shù)原型,包括返回類型、函數(shù)名、參數(shù)個(gè)數(shù)、參數(shù)類型的順序,都必須與基類中的原型相同。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用例子:#includeclass basepublic:virtual void who()coutbasen;class first:public basepublic:void who()coutthe first derivationn;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)

32、的作用class second:public basepublic:void who()coutwho(); /調(diào)用base類的who()ptr=&obj2;ptr-who(); /調(diào)用first類的who()ptr=&obj3;ptr-who(); /調(diào)用second類的who()return 1; 第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 (2)虛函數(shù)與重載函數(shù)的關(guān)系一般的函數(shù)重載,函數(shù)的返回類型及所帶的參量可以不同,僅是函數(shù)名相同即可。當(dāng)重載一個(gè)虛函數(shù)時(shí),派生類中重新定義此虛函數(shù),要求函數(shù)原型,包括返回類型、函數(shù)名、參數(shù)個(gè)數(shù)、參數(shù)類型的順序,都必須與基

33、類中的原型相同。若出現(xiàn)不同,有下面兩種情況:僅返回類型不同,系統(tǒng)會(huì)當(dāng)作出錯(cuò)處理。函數(shù)原型不同,僅函數(shù)名同,系統(tǒng)認(rèn)為它是一般的函數(shù)重載,丟失虛特性。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用#includeclass basepublic:virtual void f1()coutf1 function of base! n;virtual void f2()coutf2 function of base! n;virtual void f3()coutf3 function of base! n;void f4()coutf4 function of base! n;第6章

34、多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class derive:public basevoid f1()coutf1 function of derive! n;void f2(int x) /重載coutf2 function of derive! n;int f3(); /錯(cuò)誤,只有返回類型不同,應(yīng)去掉void f4() coutf1();ptr-f2();ptr-f3();ptr=&obj2;ptr-f1();ptr-f2();ptr-f4();return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用此例在基類中定義了3個(gè)虛函數(shù)f1(),f2(

35、),f3(),這3個(gè)函數(shù)在派生類中被重新定義時(shí),f1()符合規(guī)則,它仍為虛函數(shù);f2()增加了一個(gè)整型參量,變?yōu)閒2(int x),丟失了虛特性,變?yōu)橐话愕闹剌d函數(shù);f3()的返回類型由void變?yōu)閕nt,系統(tǒng)指出沖突的出錯(cuò)信息?;愔械膄4()函數(shù)和派生類中的f4()函數(shù)都為一般的重載函數(shù)。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用在main()函數(shù)中定義了一個(gè)基類指針ptr,在執(zhí)行過程中當(dāng)指向基類對(duì)象時(shí),用它調(diào)用的函數(shù)均為基類的成員函數(shù);當(dāng)ptr指向派生類對(duì)象obj2時(shí),ptr-f1()執(zhí)行的是派生類中的成員函數(shù),這是因?yàn)閒1()為虛函數(shù);ptr-f2()執(zhí)行的是基類的成

36、員函數(shù),因?yàn)閒2()丟失了虛特性,按照一般的重載函數(shù)來處理;ptr-f4()執(zhí)行的是基類的成員函數(shù),因?yàn)閒4()為重載函數(shù)。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用例.多態(tài)例示 #include class base public: virtual void fn() cout In base classn; ; class subclass:public base public: virtual void fn() cout In subclassn; ;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 void test(base &b) b.fn(

37、); void main() base bc; subclass sc; test(bc); test(sc); 通常將指針或引用聲明為基類的,它可以指向基類或派生類的對(duì)象。 若該指針指向一個(gè)基類的對(duì)象,那么被調(diào)用是基類的虛函數(shù); 如果指向一個(gè)派生類的對(duì)象,那么被調(diào)用的是派生類的虛函數(shù),這種機(jī)制就叫做“多態(tài)”。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用例.多態(tài)例示 #include class B public: virtual void print() coutHello Bendl; ; class D : public B public: virtual void pr

38、int() coutHello Dprint(); D d; pb = &d; pb-print(); return 0; 指向基類的指針,可以指向它的公有派生的對(duì)象,但不能指向私有派生的對(duì)象,對(duì)于引用也是一樣的。 若上例D為私有派生與B,則: B* pb = &d; / error B& rb = d; / error第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 父親的行為像兒子 從某個(gè)基類派生出多個(gè)繼承類對(duì)象,其基類有一個(gè)虛方法doit,然后其子類也有這個(gè)方法,但行為不同, 然后這些子對(duì)象中的任何一個(gè)可以賦給其基類的對(duì)象,這樣其基類的對(duì)象就可以執(zhí)行不

39、同的操作了。 通過其基類來訪問其子對(duì)象的,要做的就是一個(gè)賦值操作。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 例3.姓氏運(yùn)動(dòng)會(huì) /多態(tài)例示 李氏兩兄妹(哥哥和妹妹)參加姓氏運(yùn)動(dòng)會(huì)(不同姓氏組隊(duì)參加),哥哥男子項(xiàng)目比賽,妹妹參加女子項(xiàng)目比賽, 開幕式有一個(gè)參賽隊(duì)伍代表發(fā)言儀式,兄妹倆都想去露露臉,可只能一人去,最終他們決定到時(shí)抓鬮決定,而組委會(huì)也不反對(duì), 它才不關(guān)心是哥哥還是妹妹來發(fā)言,只要派一個(gè)姓李的來說兩句話就行。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 #include class Li public: virtual void say() ; cla

40、ss Li_brother : public Li public: virtual void say() cout Im Li ming, I have 3 sports: boxing, fencing and wrestling. endl; void boxing() cout boxing endl; void fencing() cout fencing endl; void wrestling() cout wrestling endl; ;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 class Li_sister : public Li public: virt

41、ual void say() cout Im Li xia, I have 2 sports: swim and skating. endl; void swim() cout swim endl; void skating() cout skatingsay(); int main() Li *p; /基類指針,李家代表 Li_brother b; Li_sister s; p = &s; /基類指針指向派生類Li_sister對(duì)象,獲得發(fā)言機(jī)會(huì) Speak(p); return 0; 第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用虛函數(shù)在運(yùn)行時(shí)表現(xiàn)出多態(tài)功能,這是C+

42、的精髓. 下列函數(shù)不能說明為虛的: 普通函數(shù) 構(gòu)造函數(shù) 靜態(tài)成員函數(shù)第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(3).多繼承中的虛函數(shù)在多繼承中由于派生類是由多個(gè)基類派生而來的,因而,虛函數(shù)的使用就不像單繼承那樣簡(jiǎn)單??聪旅娴睦樱?include class a public: virtual void f() /定義f()為虛函數(shù) coutclass an;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class b public: void f() /此處f()為一般函數(shù) coutclass bn;class aa:public a,public b pu

43、blic: void f() coutf(); /調(diào)用a類的f() ptr2=&obj2; ptr2-f(); /調(diào)用b類的f() ptr1=&obj3; ptr1-f(); /調(diào)用aa類的f(),此時(shí)的f()為虛函數(shù) ptr2=&obj3; ptr2-f(); /調(diào)用b類的f(),因?yàn)榇颂巉()為非虛函數(shù),而ptr2又為b類指針 return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用從上面的例子看出,派生類aa中的函數(shù)f()在不同的場(chǎng)合,呈現(xiàn)不同的性質(zhì)。若相對(duì)于a派生路徑,由于在a中的f()函數(shù)前面有關(guān)鍵字virtual,所以它是一個(gè)虛函數(shù);若

44、相對(duì)于b派生路徑,在b中的f()函數(shù)為一般函數(shù),所以它只是一個(gè)重載函數(shù)。當(dāng)a類指針指向aa類對(duì)象obj3時(shí),函數(shù)f()就呈現(xiàn)出虛特性;當(dāng)b類指針指向aa類對(duì)象obj3時(shí),函數(shù)只呈現(xiàn)一般的重載特性。運(yùn)行結(jié)果如下:class aclass bclass aaclass b第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用若一個(gè)派生類,它的多個(gè)基類中有公共的基類,在公共基類中定義一個(gè)虛函數(shù),則多級(jí)派生以后仍可以重新定義虛函數(shù),也就是說虛特性是可以傳遞的??聪旅娴睦樱?include class a public: virtual void f() coutclass an;第6章 多態(tài)性

45、與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class a1:public apublic: void f() coutclass a1n;class a2:public a public: void f() coutclass a2n;class aa:public a1,public a2 public: void f() coutf(); /調(diào)用aa類的f() ptr2=&obj; /a2類指針ptr2指向aa類對(duì)象obj ptr2-f(); /調(diào)用aa類的f() return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用運(yùn)行結(jié)果為:class aaclas

46、s aa從例子中看出,虛特性是可以傳遞的。a類作為a1和a2類的直接基類,它的成員函數(shù)f()被聲明為虛函數(shù),則a1和a2類中的f()都具有虛特性,即均為虛函數(shù);而aa類為a1和a2的派生類,因此它的成員函數(shù)f()也為虛函數(shù)。使用級(jí)聯(lián)式派生時(shí)要注意一點(diǎn),指向派生類的指針不能繼承。也就是說,基類的指針可以指向它的派生類,但不能再指向它的派生類的派生類。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用例如,在上例中若定義一個(gè)a類指針:a *ptr;它可以指向a類的派生類,例如:a1 obj1;a2 obj2;ptr=&obj1;ptr=obj2;但它不能指向其派生類的派生類aa,

47、例如:aa obj3;ptr=&obj3; /error這是極端錯(cuò)誤的。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用(4).基類構(gòu)造函數(shù)調(diào)用虛函數(shù)當(dāng)一個(gè)基類的構(gòu)造函數(shù)調(diào)用一個(gè)虛函數(shù)時(shí),會(huì)出現(xiàn)意想不到的結(jié)果??聪旅娴睦樱?include class base public: base() coutthe constructor of basen; clone(); virtual void clone() coutthe clone function of basen;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class derive:public b

48、asepublic: derive() coutthe constructor of deriven; void clone() coutclone(); return 1;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用運(yùn)行結(jié)果為:the constructor of basethe clone function of basethe constructor of derivethe clone function of derive輸出結(jié)果的第2行是出乎意料的,下面分析:第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用首先創(chuàng)建一個(gè)派生類對(duì)象obj,在創(chuàng)建時(shí)先調(diào)用基類構(gòu)

49、造函數(shù)?;悩?gòu)造函數(shù)首先輸出第一行結(jié)果,然后調(diào)用clone()函數(shù),因?yàn)榇撕瘮?shù)為虛函數(shù),并且當(dāng)前定義對(duì)象為derive類對(duì)象,照理此時(shí)應(yīng)執(zhí)行clone()在derive類中的版本,但此時(shí),派生類對(duì)象正在創(chuàng)建中,只做了部分的初始化,當(dāng)編譯器遇到要調(diào)用虛函數(shù)clone()時(shí),它無法與派生類中的clone()版本聯(lián)編,只能調(diào)用基類的clone()版本來代替它,因此出現(xiàn)第二行的意外結(jié)果。之后再執(zhí)行派生類的構(gòu)造函數(shù),輸出第三行結(jié)果。執(zhí)行到ptr-clone()時(shí),派生類對(duì)象早已圓滿創(chuàng)建,因此就可調(diào)用clone()函數(shù)的派生類版本,得到第四行的輸出結(jié)果。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函

50、數(shù)的作用虛函數(shù)舉例例1 有一個(gè)汽車類vehicle ,將它作為基類派生出小車類car、卡車類truck和輪船類boat,定義這些類并定義一個(gè)虛函數(shù)用來顯示各類信息。#include class vehicle int wheels; float weight; public: virtual void message() coutvehicle messagen;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class car:public vehicle int passenger_load; public: void message() coutcar messagen;cl

51、ass truck:public vehicle int passenger_load; float payload; public: void message() couttruck messagen;class boat:public vehicleint passenger_load; public: void message() coutmessage(); /調(diào)用基類成員函數(shù) ptr=&obj1; /將指針ptr指向car類對(duì)象 ptr-message(); /調(diào)用car類成員函數(shù) ptr=&obj2; /將指針ptr指向truck類對(duì)象 ptr-message();

52、 /調(diào)用truck類成員函數(shù) ptr=&obj3; /將指針ptr指向boat類對(duì)象 ptr-message(); /調(diào)用boat類成員函數(shù) return 1; 第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用運(yùn)行結(jié)果為:vehicle messagecar messagetruck messageboat message當(dāng)基類指針指向不同的對(duì)象,則指向不同對(duì)象所對(duì)應(yīng)類的成員函數(shù)。第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用例 現(xiàn)有三角形、正方形和圓形三種圖形,求它們各自的面積??梢詮乃鼈兂橄蟪鲆粋€(gè)基類,在基類中聲明一個(gè)虛函數(shù),用來求面積,并利用單界面、多實(shí)

53、現(xiàn)版本設(shè)計(jì)各個(gè)圖形求面積的方法。程序如下:#include class figure /定義一個(gè)公共的基類protected: int x,y;public: figure(int x,int y) figure:x=x; figure:y=y; virtual void show_area() /定義一個(gè)界面接口 coutno area for this claaan;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用class triangle:public figure /定義三角形類,基類成員x為底邊長(zhǎng),y為三角形的高public: triangle(int x,int y)

54、:figure(x,y); void show_area() /三角形類的虛函數(shù)版本 coutthe area of this triangle is:x*y*0.5n;class square:public figure /定義正方形類,基類的數(shù)據(jù)成員為正方形的邊長(zhǎng)public: square(int x):figure(x,x); void show_area() /正方形類的虛函數(shù)版本 coutthe area of this square is:x*xn;第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用 class circles:public figure /定義圓類,基

55、類的數(shù)據(jù)成員為圓的半徑public: circles(int x):figure(x,x); void show_area() coutthe area of this circle is:x*x*3.1416show_area(); ptr=&squa; /指針ptr指向正方形類對(duì)象ptr-show_area();ptr=ˆ /指針ptr指向圓類對(duì)象ptr-show_area();return 1; 第6章 多態(tài)性與虛函數(shù) 6.3.1 虛函數(shù)的作用虛函數(shù)的作用運(yùn)行結(jié)果為:the area of this triangle is:200the area of this

56、 square is:400the area of this circle is:1256.64從程序中看出,各對(duì)象都具有相同的界面:show_area(),但它們對(duì)應(yīng)不同的實(shí)現(xiàn)方法。第6章 多態(tài)性與虛函數(shù) 6.3.2 靜態(tài)關(guān)聯(lián)與動(dòng)態(tài)關(guān)聯(lián)靜態(tài)關(guān)聯(lián)與動(dòng)態(tài)關(guān)聯(lián)函數(shù)重載和通過對(duì)象名調(diào)用的虛函數(shù),在編譯時(shí)即可確定其調(diào)用的虛函數(shù)屬于哪一個(gè)類,其過程稱為靜態(tài)關(guān)聯(lián)。調(diào)用虛函數(shù)時(shí),先定義一個(gè)指向基類的指針變量,并使它指向相應(yīng)的類對(duì)象,然后通過這個(gè)基類指針去調(diào)用虛函數(shù)。編譯系統(tǒng)在編譯階段無法確定調(diào)用哪一個(gè)類對(duì)象的虛函數(shù)。在運(yùn)行階段把虛函數(shù)和類對(duì)象“綁定”在一起,因此成為動(dòng)態(tài)關(guān)聯(lián)。這種多態(tài)性是動(dòng)態(tài)的多態(tài)性,即運(yùn)行

57、階段的多態(tài)性。第6章 多態(tài)性與虛函數(shù) 6.3.3在什么情況下應(yīng)當(dāng)聲明虛函數(shù)在什么情況下應(yīng)當(dāng)聲明虛函數(shù)使用虛函數(shù)時(shí),有兩點(diǎn)要注意:(1)只能用virtual聲明類的成員函數(shù),不能將類外的普通函數(shù)聲明為虛函數(shù)。因?yàn)樘摵瘮?shù)的作用是允許在派生類中對(duì)基類的虛函數(shù)重新定義。它只能用于類的繼承層次結(jié)構(gòu)中。(2)一個(gè)成員函數(shù)被聲明為虛函數(shù)后,在同一類族中的類就不能再定義一個(gè)非virtual的但與該虛函數(shù)具有相同參數(shù)和函數(shù)返回值類型的同名函數(shù)。第6章 多態(tài)性與虛函數(shù) 6.3.3在什么情況下應(yīng)當(dāng)聲明虛函數(shù)在什么情況下應(yīng)當(dāng)聲明虛函數(shù)(1)首先看成員函數(shù)所在的類是否會(huì)作為基類。然后看成員函數(shù)在類的繼承后有無可能被更改

58、功能,如果希望更改其功能的,一般應(yīng)該將它聲明為虛函數(shù)。(2)如果成員函數(shù)在類被繼承后功能不需要修改,或派生類用不到該函數(shù),則不用把它聲明為虛函數(shù)。不要僅僅考慮到要作為基類而把類中的所以成員函數(shù)都聲明為虛函數(shù)。(3)應(yīng)考慮對(duì)成員函數(shù)的調(diào)用是通過對(duì)象名還是通過基類指針或引用去訪問,如果是通過基類指針或引用去訪問的,則應(yīng)當(dāng)聲明為虛函數(shù)。(4)有時(shí),在定義虛函數(shù)時(shí),并不定義其函數(shù)體,即函數(shù)體是空的。它的作用只是定義了一個(gè)虛函數(shù)名,具體功能留給派生類去添加。第6章 多態(tài)性與虛函數(shù) 6.3.4虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)當(dāng)派生類的對(duì)象從內(nèi)存中撤銷時(shí)一般先調(diào)用派生類的析構(gòu)函數(shù),然后再調(diào)用基類的析構(gòu)函數(shù)。但是,如果用

59、new運(yùn)算符建立了臨時(shí)對(duì)象,若基類中有析構(gòu)函數(shù),并且定義了一個(gè)指向該基類的指針變量。在程序用帶指針參數(shù)的delete運(yùn)算符撤銷對(duì)象時(shí),會(huì)發(fā)生一個(gè)情況:系統(tǒng)會(huì)只執(zhí)行基類的析構(gòu)函數(shù),而不執(zhí)行派生類的析構(gòu)函數(shù)。例:基類中有非虛析構(gòu)函數(shù)時(shí)的執(zhí)行情況。第6章 多態(tài)性與虛函數(shù) 6.3.4虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)#include using namespace std;class Pointpublic: Point() Point()coutexectuing Point destructorendl;class Circle:public Pointpublic: Circle() Circle()cout

60、executing Circle destructorendl; private: in radius; ;int main()Point *p=new Circle; delete p; return 0;第6章 多態(tài)性與虛函數(shù) 6.3.4虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)運(yùn)行結(jié)果:exectuing Point destructor程序分析:希望用delete釋放p所指向的空間,結(jié)果只執(zhí)行了基類Point的析構(gòu)函數(shù),而沒有執(zhí)行派生類circle的析構(gòu)函數(shù)。如果希望執(zhí)行派生類circle的析構(gòu)函數(shù),可以將基類的析構(gòu)函數(shù)聲明為虛析構(gòu)函數(shù),如virtual Point()coutexectuing Point destructorendl;程序其他部分不變,再運(yùn)行程序,結(jié)果為:exectuing Circle destructorexectuing Point destructor第6章 多態(tài)性與虛函數(shù) 6.3.4虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)當(dāng)基類的析構(gòu)函數(shù)為虛函數(shù)時(shí),無論指針指的是同一類族中的哪一個(gè)類對(duì)象,系統(tǒng)都會(huì)采用動(dòng)態(tài)關(guān)聯(lián),調(diào)用相應(yīng)類的析構(gòu)函數(shù),對(duì)該對(duì)象進(jìn)行清理工作。如果將基類的析構(gòu)函數(shù)聲明為

溫馨提示

  • 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)論