譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件

上傳人:英*** 文檔編號(hào):78723557 上傳時(shí)間:2022-04-22 格式:PPTX 頁(yè)數(shù):55 大小:179.52KB
收藏 版權(quán)申訴 舉報(bào) 下載
譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件_第1頁(yè)
第1頁(yè) / 共55頁(yè)
譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件_第2頁(yè)
第2頁(yè) / 共55頁(yè)
譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件_第3頁(yè)
第3頁(yè) / 共55頁(yè)

下載文檔到電腦,查找使用更方便

20 積分

下載資源

還剩頁(yè)未讀,繼續(xù)閱讀

資源描述:

《譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件》由會(huì)員分享,可在線閱讀,更多相關(guān)《譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件(55頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。

1、多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O(shè)計(jì)的一個(gè)重要特征。利用多態(tài)性可以設(shè)計(jì)和實(shí)現(xiàn)一個(gè)易于擴(kuò)展的系統(tǒng)。p在C+程序設(shè)計(jì)中,多態(tài)性是指具有不同功能的函數(shù)可以用同一個(gè)函數(shù)名,這樣就可以用一個(gè)函數(shù)名調(diào)用不同內(nèi)容的函數(shù)。p在面向?qū)ο蠓椒ㄖ械亩鄳B(tài)性: 向不同的對(duì)象發(fā)送同一個(gè)消息(函數(shù)名),不同的對(duì)象在接收時(shí)會(huì)產(chǎn)生不同的行為(即方法)。也就是說(shuō),每個(gè)對(duì)象可以用自己的方式去響應(yīng)共同的消息。12.1 多態(tài)性的概念第1頁(yè)/共55頁(yè)優(yōu)點(diǎn):在C+程序設(shè)計(jì)中,在不同的類(lèi)中定義了其響應(yīng)消息的方法,那么使用這些類(lèi)時(shí),不必考慮它們是什么類(lèi)型,只要發(fā)布消息即可。多態(tài)性分為兩類(lèi): 靜態(tài)多態(tài)性和動(dòng)態(tài)多態(tài)性。p靜態(tài)多態(tài)性

2、:函數(shù)重載和運(yùn)算符重載屬于靜態(tài)多態(tài)性,在程序編譯時(shí)系統(tǒng)就能決定調(diào)用的是哪個(gè)函數(shù),因此靜態(tài)多態(tài)性又稱(chēng)編譯時(shí)的多態(tài)性。p動(dòng)態(tài)多態(tài)性:是在程序運(yùn)行過(guò)程中才動(dòng)態(tài)地確定操作所針對(duì)的對(duì)象。它又稱(chēng)運(yùn)行時(shí)的多態(tài)性。動(dòng)態(tài)多態(tài)性是通過(guò)虛函數(shù)(virtual function)實(shí)現(xiàn)的。在本章中主要介紹動(dòng)態(tài)多態(tài)性和虛函數(shù)。第2頁(yè)/共55頁(yè)下面是一個(gè)承上啟下的例子。一方面它是有關(guān)繼承和運(yùn)算符重載內(nèi)容的綜合應(yīng)用的例子,通過(guò)這個(gè)例子可以進(jìn)一步融會(huì)貫通前面所學(xué)的內(nèi)容,另一方面又是作為討論多態(tài)性的一個(gè)基礎(chǔ)用例。12.2 一個(gè)典型的例子第3頁(yè)/共55頁(yè)例12.1 先建立一個(gè)Point(點(diǎn))類(lèi),包含數(shù)據(jù)成員x,y(坐標(biāo)點(diǎn))。以它為

3、基類(lèi),派生出一個(gè)Circle(圓)類(lèi),增加數(shù)據(jù)成員r(半徑),再以Circle類(lèi)為直接基類(lèi),派生出一個(gè)Cylinder(圓柱體)類(lèi),再增加數(shù)據(jù)成員h(高)。要求編寫(xiě)程序,重載運(yùn)算符“”,使之能用于輸出以上類(lèi)對(duì)象。對(duì)于一個(gè)比較大的程序,應(yīng)當(dāng)分成若干步驟進(jìn)行。先聲明基類(lèi),再聲明派生類(lèi),逐級(jí)進(jìn)行,分步調(diào)試。(1) 聲明基類(lèi)Point類(lèi) 寫(xiě)出聲明基類(lèi)Point的部分:#include /聲明類(lèi)Point /聲明一個(gè)類(lèi)包括什么?class Pointpublic: Point(float x=0,float y=0);/有默認(rèn)參數(shù)的構(gòu)造函數(shù)第4頁(yè)/共55頁(yè) void setPoint(float,flo

4、at); /設(shè)置坐標(biāo)值 float getX( ) const return x; /讀x坐標(biāo) float getY( ) const return y; /讀y坐標(biāo) friend ostream & operator(ostream &,const Point &);/重載運(yùn)算符“”protected: /受保護(hù)成員 float x,y;/下面定義Point類(lèi)的成員函數(shù) /Point的構(gòu)造函數(shù)Point:Point(float a,float b) /對(duì)x,y初始化x=a;y=b;/設(shè)置x和y的坐標(biāo)值void Point:setPoint(float a,float b) /為x,y賦新值x

5、=a;y=b;/重載運(yùn)算符“”,使之能輸出點(diǎn)的坐標(biāo)ostream & operator(ostream &output,const Point &p)outputp.x,p.yendl; return output;以上完成了基類(lèi)Point類(lèi)的聲明。第5頁(yè)/共55頁(yè)現(xiàn)在要對(duì)上面寫(xiě)的基類(lèi)聲明進(jìn)行調(diào)試,檢查它是否有錯(cuò),為此要寫(xiě)出main函數(shù)。實(shí)際上它是一個(gè)測(cè)試程序。int main( )Point p(3.5,6.4);/建立Point類(lèi)對(duì)象p coutx=p.getX( ),y=p.getY( )endl;/輸出p的坐標(biāo)值 p.setPoint(8.5,6.8); /重新設(shè)置p的坐標(biāo)值 cout

6、p(new):pendl; /用重載運(yùn)算符“”輸出p點(diǎn)坐標(biāo)程序編譯通過(guò),運(yùn)行結(jié)果為x=3.5,y=6.4p(new):8.5,6.8測(cè)試程序檢查了基類(lèi)中各函數(shù)的功能,以及運(yùn)算符重載的作用,證明程序是正確的。第6頁(yè)/共55頁(yè)(2) 聲明派生類(lèi)Circleclass Circle:public Point/circle是Point類(lèi)的公用派生類(lèi)public: Circle(float x=0,float y=0,float r=0); /構(gòu)造函數(shù) void setRadius(float); /設(shè)置半徑值 float getRadius( ) const; /讀取半徑值 float area (

7、) const; /計(jì)算圓面積 friend ostream &operator(ostream &,const Circle &);/重載運(yùn)算符“” private:/?protected: float radius;/定義構(gòu)造函數(shù),對(duì)圓心坐標(biāo)和半徑初始化Circle:Circle(float a,float b,float r):Point(a,b),radius(r) void Circle:setRadius(float r) /設(shè)置半徑值radius=r;float Circle:getRadius( ) const return radius; /讀取半徑值float Circle

8、:area( ) const第7頁(yè)/共55頁(yè)return 3.14159*radius*radius;/重載運(yùn)算符“”,使之按規(guī)定的形式輸出圓的信息ostream &operator(ostream &output,const Circle &c)outputCenter=c.x,c.y,r=c.radius,area=c.area( )endl; return output;為了測(cè)試Circle類(lèi)的定義,可以寫(xiě)出下面的主函數(shù):第8頁(yè)/共55頁(yè)i n t m a i n ( ) C i r c l e c ( 3 . 5 , 6 . 4 , 5 . 2 ) ; / / 建 立 C i r c

9、l e 類(lèi) 對(duì) 象 c , 并 給 定 圓 心 坐 標(biāo) 和 半 徑 c o u t o r i g i n a l c i r c l e : n x = c . g e t X ( ) , y = c . g e t Y ( ) , r = c . g e t R a d i u s ( ) , a r e a = c . a r e a ( ) e n d l ; / / 輸 出 圓 心 坐 標(biāo) 、 半 徑 和 面 積 c . s e t R a d i u s ( 7 . 5 ) ; / / 設(shè) 置 半 徑 值 c . s e t P o i n t ( 5 , 5 ) ; / / 設(shè)

10、置 圓 心 坐 標(biāo) 值 x , y c o u t n e w c i r c l e : n c ; / / 用 重 載 運(yùn) 算 符 “ ” 輸 出 圓 對(duì) 象 的 信 息 P o i n t & p R e f = c ; / / p R e f 是 P o i n t 類(lèi) 的 引 用 變 量 , 被 c 初 始 化 c o u t p R e f : p R e f ; / / 輸 出 p R e f 的 信 息 r e t u r n 0 ;程 序 編 譯 通 過(guò) , 運(yùn) 行 結(jié) 果 為 o r i g i n a l c i r c l e : ( 輸 出 原 來(lái) 的 圓 的 數(shù) 據(jù)

11、 )x = 3 . 5 , y = 6 . 4 , r = 5 . 2 , a r e a = 8 4 . 9 4 8 6n e w c i r c l e : ( 輸 出 修 改 后 的 圓 的 數(shù) 據(jù) )C e n t e r = 5 , 5 , r = 7 . 5 , a r e a = 1 7 6 . 7 1 4p R e f : 5 , 5 ( 輸 出 圓 的 圓 心 “ 點(diǎn) ” 的 數(shù) 據(jù) )第9頁(yè)/共55頁(yè)(3) 聲明Circle的派生類(lèi)Cylinderclass Cylinder:public Circle/ Cylinder是Circle的公用派生類(lèi)public: Cylin

12、der (float x=0,float y=0,float r=0,float h=0);/構(gòu)造函數(shù) void setHeight(float); /設(shè)置圓柱高 float getHeight( ) const; /讀取圓柱高 float area( ) const; /計(jì)算圓表面積 float volume( ) const; /計(jì)算圓柱體積 friend ostream& operator(ostream&,const Cylinder&);/重載運(yùn)算符“” protected: float height; /圓柱高;Cylinder:Cylinder(float a,float b,f

13、loat r,float h) /定義構(gòu)造函數(shù) :Circle(a,b,r),height(h)void Cylinder:setHeight(float h)height=h; /設(shè)置圓柱高float Cylinder:getHeight( ) const return height; /讀取圓柱高第10頁(yè)/共55頁(yè)/計(jì)算圓表面積float Cylinder:area( ) const return 2*Circle:area( )+2*3.14159*radius*height;float Cylinder:volume() const/計(jì)算圓柱體積return Circle:area()

14、*height;/重載運(yùn)算符“”ostream &operator(ostream &output,const Cylinder& cy)outputCenter=cy.x,cy.y,r=cy.radius,h=cy.height narea=cy.area( ), volume=cy.volume( )endl; return output;第11頁(yè)/共55頁(yè) 可以寫(xiě)出下面的主函數(shù): int main( )Cylinder cy1(3.5,6.4,5.2,10);/定義Cylinder類(lèi)對(duì)象cy1 coutn original cylinder:nx=cy1.getX( ), y=cy1.g

15、etY( ), 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.5); /設(shè)置圓半徑 cy1.setPoint(5,5); /設(shè)置圓心坐標(biāo)值x,y coutnnew cylinder:ncy1; /用重載運(yùn)算符“”輸出cy1的數(shù)據(jù) Point &pRef=cy1; /pRef是Point類(lèi)對(duì)象的引用變量第12頁(yè)/共55頁(yè) coutnpRef as a Poi

16、nt:pRef; /pRef作為一個(gè)“點(diǎn)”輸出 Circle &cRef=cy1; /cRef是Circle類(lèi)對(duì)象的引用變量 coutncRef as a Circle:display( );”可以調(diào)用不同派生層次中的display函數(shù),只需在調(diào)用前給指針變量pt賦以不同的值(使之指向不同的類(lèi)對(duì)象)即可。C+中的虛函數(shù)就是用來(lái)解決這個(gè)問(wèn)題的。虛函數(shù)的作用是允許在派生類(lèi)中重新定義與基類(lèi)同名的函數(shù),并且可以通過(guò)基類(lèi)指針或引用來(lái)訪問(wèn)基類(lèi)和派生類(lèi)中的同名函數(shù)。方法:由基類(lèi)指針,訪問(wèn)各層次中的同名函數(shù)。例12.2。再討論使用虛函數(shù)的情況。第15頁(yè)/共55頁(yè)例12.2 基類(lèi)與派生類(lèi)中有同名函數(shù)。在下面的程

17、序中Student是基類(lèi),Graduate是派生類(lèi),它們都有display這個(gè)同名的函數(shù)。#include #include using namespace std;/聲明基類(lèi)Studentclass Studentpublic: Student(int, string,float);/聲明構(gòu)造函數(shù) void display( ); /聲明輸出函數(shù) protected: /受保護(hù)成員,派生類(lèi)可以訪問(wèn) int num; string name; float score; ;第16頁(yè)/共55頁(yè) /Student類(lèi)成員函數(shù)的實(shí)現(xiàn)Student:Student(int n, string nam,fl

18、oat s) /定義構(gòu)造函數(shù) num=n;name=nam;score=s;void Student:display( ) /定義輸出函數(shù)coutnum:numnname:namenscore:scorenn;第17頁(yè)/共55頁(yè)/聲明公用派生類(lèi)Graduateclass Graduate:public Studentpublic: Graduate(int, string, float, float); /聲明構(gòu)造函數(shù) void display( ); /聲明輸出函數(shù)private: float pay;/ Graduate類(lèi)成員函數(shù)的實(shí)現(xiàn)void Graduate:display( ) /定

19、義輸出函數(shù) coutnum:numnname:namenscore:scorenpay=paydisplay( ); pt=&grad1; pt-display( ); return 0; 第19頁(yè)/共55頁(yè)運(yùn)行結(jié)果如下,請(qǐng)仔細(xì)分析。num:1001(stud1的數(shù)據(jù))name:Liscore:87.5num:2001 (僅輸出了grad1中基類(lèi)部分的數(shù)據(jù),沒(méi)實(shí)現(xiàn)多態(tài)性!)name:wangscore:98.5下面對(duì)程序作一點(diǎn)修改,在Student類(lèi)中聲明display函數(shù)時(shí),在最左面加一個(gè)關(guān)鍵字virtual,即virtual void display( );變成虛函數(shù)就行了這樣就把Stud

20、ent類(lèi)的display函數(shù)聲明為虛函數(shù)。程序其他部分都不改動(dòng)。再編譯和運(yùn)行程序,請(qǐng)注意分析運(yùn)行結(jié)果: 第20頁(yè)/共55頁(yè)num:1001(stud1的數(shù)據(jù))name:Liscore:87.5num:2001 (grad1中基類(lèi)部分的數(shù)據(jù),達(dá)到目的!)name:wangscore:98.5pay=1200 (這一項(xiàng)以前是沒(méi)有的)由虛函數(shù)實(shí)現(xiàn)的動(dòng)態(tài)多態(tài)性就是: 同一類(lèi)族中不同類(lèi)的對(duì)象,對(duì)同一函數(shù)調(diào)用作出不同的響應(yīng)。多態(tài)性理解:起始地址相同的不同對(duì)象指針,調(diào)同名函數(shù)時(shí),響應(yīng)不同(調(diào)了各自對(duì)應(yīng)的函數(shù))。實(shí)現(xiàn)方法:將同名函數(shù)聲明為虛函數(shù)。第21頁(yè)/共55頁(yè)虛函數(shù)的使用方法是: 注意規(guī)則! (1) 在基

21、類(lèi)用virtual聲明成員函數(shù)為虛函數(shù)。這樣就可以在派生類(lèi)中重新定義此函數(shù),為它賦予新的功能,并能方便地被調(diào)用。 在類(lèi)外定義虛函數(shù)時(shí),不必再加virtual。(2) 在派生類(lèi)中重新定義此函數(shù),要求函數(shù)名、函數(shù)類(lèi)型、函數(shù)參數(shù)個(gè)數(shù)和類(lèi)型全部與基類(lèi)的虛函數(shù)相同,并根據(jù)派生類(lèi)的需要重新定義函數(shù)體。 第22頁(yè)/共55頁(yè)C+規(guī)定,當(dāng)一個(gè)成員函數(shù)被聲明為虛函數(shù)后,其派生類(lèi)中的同名函數(shù)都自動(dòng)成為虛函數(shù)。因此在派生類(lèi)重新聲明該虛函數(shù)時(shí),可以加virtual,也可以不加,但習(xí)慣上一般在每一層聲明該函數(shù)時(shí)都加virtual,使程序更加清晰。如果在派生類(lèi)中沒(méi)有對(duì)基類(lèi)的虛函數(shù)重新定義,則派生類(lèi)簡(jiǎn)單地繼承其直接基類(lèi)的虛函

22、數(shù)。(3) 必須定義一個(gè)指向基類(lèi)對(duì)象的指針變量,并使它指向同一類(lèi)族中需要調(diào)用該函數(shù)的對(duì)象。(4) 通過(guò)該指針變量調(diào)用此虛函數(shù),此時(shí)調(diào)用的就是指針變量指向的對(duì)象的同名函數(shù)。第23頁(yè)/共55頁(yè)舉例2 :用引用也可,如將上面例題改為void fun( Student & x)/必須為基類(lèi)指針或引用! x.display( );/主函數(shù)int main() Student s1(1001,Li,87.5); Graduate gd1(2001,Wang,98.5,563.5); fun( s1); fun (gd1); return 0;第24頁(yè)/共55頁(yè)顯示結(jié)果:num:1001(stud1的數(shù)據(jù))

23、name:Liscore:87.5num:2001 (grad1的數(shù)據(jù))name:wangscore:98.5pay=1200第25頁(yè)/共55頁(yè)注意區(qū)別:函數(shù)重載處理的是同一層次上的同名函數(shù)問(wèn)題,而虛函數(shù)處理的是不同派生層次上的同名函數(shù)問(wèn)題,前者是橫向重載,后者可以理解為縱向重載。但與重載不同的是: 同一類(lèi)族的虛函數(shù)的首部是相同的,而函數(shù)重載時(shí)函數(shù)的首部是不同的(參數(shù)個(gè)數(shù)或類(lèi)型不同)。第26頁(yè)/共55頁(yè)這樣編譯系統(tǒng)在對(duì)程序進(jìn)行編譯時(shí),即能確定調(diào)用的是哪個(gè)類(lèi)對(duì)象中的函數(shù)。確定調(diào)用的具體對(duì)象的過(guò)程稱(chēng)為關(guān)聯(lián)(binding)。在這里是指把一個(gè)函數(shù)名與一個(gè)類(lèi)對(duì)象捆綁在一起,建立關(guān)聯(lián)。一般地說(shuō),關(guān)聯(lián)指把

24、一個(gè)標(biāo)識(shí)符和一個(gè)存儲(chǔ)地址聯(lián)系起來(lái)。12.3.2 靜態(tài)關(guān)聯(lián)與動(dòng)態(tài)關(guān)聯(lián) 第27頁(yè)/共55頁(yè)函數(shù)重載和通過(guò)對(duì)象名調(diào)用的虛函數(shù),在編譯時(shí)即可確定其調(diào)用的虛函數(shù)屬于哪一個(gè)類(lèi),其過(guò)程稱(chēng)為靜態(tài)關(guān)聯(lián)(static binding),由于是在運(yùn)行前進(jìn)行關(guān)聯(lián)的,故又稱(chēng)為早期關(guān)聯(lián)(early binding)。函數(shù)重載屬靜態(tài)關(guān)聯(lián)。 而運(yùn)行時(shí)的多態(tài)性,編譯系統(tǒng)在編譯該行時(shí)是無(wú)法確定調(diào)用哪一個(gè)類(lèi)對(duì)象的虛函數(shù)的。因?yàn)榫幾g只作靜態(tài)的語(yǔ)法檢查,光從語(yǔ)句形式是無(wú)法確定調(diào)用對(duì)象的。第28頁(yè)/共55頁(yè)例如,先使pt指向grad1,再執(zhí)行“pt-display( )”,當(dāng)然是調(diào)用grad1中的display函數(shù)。由于是在運(yùn)行階段把虛

25、函數(shù)和類(lèi)對(duì)象“綁定”在一起的,因此,此過(guò)程稱(chēng)為動(dòng)態(tài)關(guān)聯(lián)(dynamic binding)。這種多態(tài)性是動(dòng)態(tài)的多態(tài)性,即運(yùn)行階段的多態(tài)性。在運(yùn)行階段,指針可以先后指向不同的類(lèi)對(duì)象,從而調(diào)用同一類(lèi)族中不同類(lèi)的虛函數(shù)。由于動(dòng)態(tài)關(guān)聯(lián)是在編譯以后的運(yùn)行階段進(jìn)行的,因此也稱(chēng)為滯后關(guān)聯(lián)(late binding)。第29頁(yè)/共55頁(yè)使用虛函數(shù)時(shí),有兩點(diǎn)要注意: (1)只能用virtual聲明類(lèi)的成員函數(shù),使它成為虛函數(shù),而不能將類(lèi)外的普通函數(shù)聲明為虛函數(shù)。因?yàn)樘摵瘮?shù)的作用:是允許在派生類(lèi)中對(duì)基類(lèi)的虛函數(shù)重新定義。顯然,它只能用于類(lèi)的繼承層次結(jié)構(gòu)中。12.3.3 在什么情況下應(yīng)當(dāng)聲明虛函數(shù)第30頁(yè)/共55頁(yè)(

26、2) 應(yīng)考慮對(duì)成員函數(shù)的調(diào)用是通過(guò)對(duì)象名還是通過(guò)基類(lèi)指針或引用去訪問(wèn),如果是通過(guò)基類(lèi)指針或引用去訪問(wèn)的,則應(yīng)當(dāng)聲明為虛函數(shù)。需要說(shuō)明的是: 使用虛函數(shù),系統(tǒng)要有一定的空間開(kāi)銷(xiāo)。當(dāng)一個(gè)類(lèi)帶有虛函數(shù)時(shí),編譯系統(tǒng)會(huì)為該類(lèi)構(gòu)造一個(gè)虛函數(shù)表(virtual function table,簡(jiǎn)稱(chēng)vtable),它是一個(gè)指針數(shù)組,存放每個(gè)虛函數(shù)的入口地址。系統(tǒng)在進(jìn)行動(dòng)態(tài)關(guān)聯(lián)時(shí)的時(shí)間開(kāi)銷(xiāo)是很少的,因此,多態(tài)性是高效的。第31頁(yè)/共55頁(yè)多態(tài)性進(jìn)一步理解:多態(tài)性是指在運(yùn)行時(shí),能根據(jù)其類(lèi)型確認(rèn)調(diào)用哪個(gè)函數(shù)的能力。只支持類(lèi)而不支持多態(tài),稱(chēng)基于對(duì)象的;如VB。只有支持多態(tài),才成為面向?qū)ο蟮?。好處分析:如?jì)算學(xué)生的學(xué)費(fèi),

27、有大學(xué)生,研究生,博士生等。從程序設(shè)計(jì)看,用采取繼承方式設(shè)計(jì)。希望只有一個(gè)收費(fèi)員(函數(shù))可以收各種學(xué)生的費(fèi)用。 而不是首先有一個(gè)管理者判斷是什么學(xué)生?再分派給各個(gè)類(lèi)型的收費(fèi)員(函數(shù))去收費(fèi)。 希望只有一個(gè)收費(fèi)員void fn(Student &x) x.calcTuition();若不這樣, fn中要判斷,分別調(diào)用,維護(hù)量大,面向?qū)ο髢?yōu)越性被限制,又回到面向過(guò)程。 第32頁(yè)/共55頁(yè)析構(gòu)函數(shù)的作用是在對(duì)象撤銷(xiāo)之前做必要的“清理現(xiàn)場(chǎng)”的工作。當(dāng)派生類(lèi)的對(duì)象從內(nèi)存中撤銷(xiāo)時(shí)一般先調(diào)用派生類(lèi)的析構(gòu)函數(shù),然后再調(diào)用基類(lèi)的析構(gòu)函數(shù)。但用delete 刪除對(duì)象時(shí)存在如下問(wèn)題,即沒(méi)有達(dá)到期望的目標(biāo)。如何解決?

28、12.3.4 虛析構(gòu)函數(shù)(還有什么函數(shù)可以虛之?)(還有什么函數(shù)可以虛之?)第33頁(yè)/共55頁(yè)例12.3 基類(lèi)中有非虛析構(gòu)函數(shù)時(shí)的執(zhí)行情況。#include using namespace std;class Point/定義基類(lèi)Point類(lèi)public: Point( ) /Point類(lèi)構(gòu)造函數(shù) Point()coutexecuting Point destructorendl;/Point類(lèi)析構(gòu)函數(shù);class Circle:public Point /定義派生類(lèi)Circle類(lèi)public: Circle( ) /Circle類(lèi)構(gòu)造函數(shù) Circle( )coutexecuting Cir

29、cle destructorendl;/Circle類(lèi)析構(gòu)函數(shù) private: int radius;第34頁(yè)/共55頁(yè)int main( ) Point *p=new Circle; /用new開(kāi)辟動(dòng)態(tài)存儲(chǔ)空間delete p; /用delete釋放動(dòng)態(tài)存儲(chǔ)空間return 0;這只是一個(gè)示意的程序。p是指向基類(lèi)的指針變量,指向new開(kāi)辟的動(dòng)態(tài)存儲(chǔ)空間,希望用detele釋放p所指向的空間,即元類(lèi)對(duì)象的空間。但運(yùn)行結(jié)果為executing Point destructor表示只執(zhí)行了基類(lèi)Point的析構(gòu)函數(shù),而沒(méi)有執(zhí)行派生類(lèi)Circle的析構(gòu)函數(shù)。第35頁(yè)/共55頁(yè)原因是:如果希望能執(zhí)行派

30、生類(lèi)Circle的析構(gòu)函數(shù),方法:可以將基類(lèi)的析構(gòu)函數(shù)聲明為虛析構(gòu)函數(shù),如virtual Point()coutexecuting Point destructorendl;程序其他部分不改動(dòng),再運(yùn)行程序,結(jié)果為executing Circle destructorexecuting Point destructor先調(diào)用了派生類(lèi)的析構(gòu)函數(shù),再調(diào)用了基類(lèi)的析構(gòu)函數(shù),符合人們的愿望。第36頁(yè)/共55頁(yè)特點(diǎn)與好處:如果將基類(lèi)的析構(gòu)函數(shù)聲明為虛函數(shù)時(shí),由該基類(lèi)所派生的所有派生類(lèi)的析構(gòu)函數(shù)也都自動(dòng)成為虛函數(shù)。這樣,如果程序中顯式地用了delete運(yùn)算符準(zhǔn)備刪除一個(gè)對(duì)象,而delete運(yùn)算符的操作對(duì)象用

31、了指向派生類(lèi)對(duì)象的基類(lèi)指針,則系統(tǒng)會(huì)調(diào)用相應(yīng)類(lèi)的析構(gòu)函數(shù)。一般即使基類(lèi)并不需要析構(gòu)函數(shù),也顯式地定義一個(gè)函數(shù)體為空的虛析構(gòu)函數(shù),以保證在撤銷(xiāo)動(dòng)態(tài)分配空間時(shí)能得到正確的處理。構(gòu)造函數(shù)不能聲明為虛函數(shù)。這是因?yàn)樵趫?zhí)行構(gòu)造函數(shù)時(shí)類(lèi)對(duì)象還未完成建立過(guò)程,當(dāng)然談不上函數(shù)與類(lèi)對(duì)象的綁定。第37頁(yè)/共55頁(yè)例如在本章的例12.1程序中,基類(lèi)Point中沒(méi)有求面積的area函數(shù),因?yàn)椤包c(diǎn)”是沒(méi)有面積的,也就是說(shuō),基類(lèi)本身不需要這個(gè)函數(shù),所以在例12.1程序中的Point類(lèi)中沒(méi)有定義area函數(shù)。但是,在其直接派生類(lèi)Circle和間接派生類(lèi)Cylinder中都需要有area函數(shù),而且這兩個(gè)area函數(shù)的功能不同

32、,一個(gè)是求圓面積,一個(gè)是求圓柱體表面積。僅供派生而無(wú)實(shí)際意義的函數(shù),故純虛之。12.4 純虛函數(shù)與抽象類(lèi) 12.4.1 純虛函數(shù)第38頁(yè)/共55頁(yè)有的讀者自然會(huì)想到,在這種情況下應(yīng)當(dāng)將area聲明為虛函數(shù)??梢栽诨?lèi)Point中加一個(gè)area函數(shù),并聲明為虛函數(shù): virtual float area( ) const return 0;其返回值為0,表示“點(diǎn)”是沒(méi)有面積的。為簡(jiǎn)化,可以不寫(xiě)出這種無(wú)意義的函數(shù)體,只給出函數(shù)的原型,并在后面加上“=0”,如virtual float area( ) const =0;/純虛函數(shù)這就將area聲明為一個(gè)純虛函數(shù)(pure virtual funct

33、ion)。純虛函數(shù)是在聲明虛函數(shù)時(shí)被“初始化”為0的函數(shù)。聲明純虛函數(shù)的一般形式是virtual 函數(shù)類(lèi)型 函數(shù)名 (參數(shù)表列) =0;第39頁(yè)/共55頁(yè)注意: 純虛函數(shù)沒(méi)有函數(shù)體;最后面的“=0”并不表示函數(shù)返回值為0,告訴編譯系統(tǒng)“這是純虛函數(shù)”; 這是一個(gè)聲明語(yǔ)句,最后應(yīng)有分號(hào)。純虛函數(shù)的作用:純虛函數(shù)只有函數(shù)的名字而不具備函數(shù)的功能。它只是通知編譯系統(tǒng): “在這里聲明一個(gè)虛函數(shù),留待派生類(lèi)中定義”。純虛函數(shù)的作用是在基類(lèi)中為其派生類(lèi)保留一個(gè)函數(shù)的名字,以便派生類(lèi)根據(jù)需要對(duì)它進(jìn)行定義。如果在基類(lèi)中沒(méi)有保留函數(shù)名字,則無(wú)法實(shí)現(xiàn)多態(tài)性。如果在一個(gè)類(lèi)中聲明了純虛函數(shù),而在其派生類(lèi)中沒(méi)有對(duì)該函數(shù)

34、定義,則該虛函數(shù)在派生類(lèi)中仍然為純虛函數(shù)。第40頁(yè)/共55頁(yè)如果聲明了一個(gè)類(lèi),一般可以用它定義對(duì)象。但是在面向?qū)ο蟪绦蛟O(shè)計(jì)中,往往有一些類(lèi),它們不用來(lái)生成對(duì)象。定義這些類(lèi)的惟一目的是用它作為基類(lèi)去建立派生類(lèi)。這種不用來(lái)定義對(duì)象而只作為一種基本類(lèi)型用作繼承的類(lèi),稱(chēng)為抽象類(lèi)(abstract class),由于它常用作基類(lèi),通常稱(chēng)為抽象基類(lèi)(abstract base class)。12.4.2 抽象類(lèi)第41頁(yè)/共55頁(yè)凡是包含純虛函數(shù)的類(lèi)都是抽象類(lèi)。因?yàn)榧兲摵瘮?shù)是不能被調(diào)用的,包含純虛函數(shù)的類(lèi)是無(wú)法建立對(duì)象的。抽象類(lèi)的作用是作為一個(gè)類(lèi)族的共同基類(lèi),或者說(shuō),為一個(gè)類(lèi)族提供一個(gè)公共接口。抽象類(lèi)的條件

35、:包含純虛函數(shù)使用規(guī)則:如果在抽象類(lèi)所派生出的新類(lèi)中對(duì)基類(lèi)的所有純虛函數(shù)進(jìn)行了定義,那么這些函數(shù)就被賦予了功能,可以被調(diào)用。這個(gè)派生類(lèi)就不是抽象類(lèi),而是可以用來(lái)定義對(duì)象的具體類(lèi)(concrete class)。如果在派生類(lèi)中沒(méi)有對(duì)所有純虛函數(shù)進(jìn)行定義,則此派生類(lèi)仍然是抽象類(lèi),不能用來(lái)定義對(duì)象。第42頁(yè)/共55頁(yè)雖然抽象類(lèi)不能定義對(duì)象(或者說(shuō)抽象類(lèi)不能實(shí)例化),但是可以定義指向抽象類(lèi)數(shù)據(jù)的指針變量。當(dāng)派生類(lèi)成為具體類(lèi)之后,就可以用這種指針指向派生類(lèi)對(duì)象,然后通過(guò)該指針調(diào)用虛函數(shù),實(shí)現(xiàn)多態(tài)性的操作??偨Y(jié):抽象類(lèi)的實(shí)際作用:定義指向抽象類(lèi)的指針,實(shí)現(xiàn)多態(tài)性操作。即對(duì)各純虛函數(shù)可實(shí)現(xiàn)多態(tài)性操作。第43

36、頁(yè)/共55頁(yè)例12.4 虛函數(shù)和抽象基類(lèi)的應(yīng)用。在本章例12.1介紹了以Point為基類(lèi)的點(diǎn)圓圓柱體類(lèi)的層次結(jié)構(gòu)。現(xiàn)在要對(duì)它進(jìn)行改寫(xiě),在程序中使用虛函數(shù)和抽象基類(lèi)。類(lèi)的層次結(jié)構(gòu)的頂層是抽象基類(lèi)Shape(形狀)。Point(點(diǎn)), Circle(圓), Cylinder(圓柱體)都是Shape類(lèi)的直接派生類(lèi)和間接派生類(lèi)。下面是一個(gè)完整的程序,為了便于閱讀,分段插入了一些文字說(shuō)明。程序如下: 12.4.3 應(yīng)用實(shí)例第44頁(yè)/共55頁(yè)第(1)部分#include using namespace std;/ /聲明抽象基類(lèi)Shape 因含純虛函數(shù)!class Shape /目的:可使各純虛函數(shù)實(shí)現(xiàn)多

37、態(tài)性public: virtual float area( ) const return 0.0;/虛函數(shù) virtual float volume() const return 0.0; /虛函數(shù) virtual void shapeName() const =0; /純虛函數(shù); /第(2)部分/聲明Point類(lèi)class Point:public Shape/Point是Shape的公用派生類(lèi)public: Point(float=0,float=0); void setPoint(float,float); float getX( ) const return x; float getY

38、( ) const return y; virtual void shapeName( ) const coutPoint:; /對(duì)虛函數(shù)進(jìn)行再定義 friend ostream & operator(ostream &,const Point &);protected: float x,y;第45頁(yè)/共55頁(yè) ; Point:Point(float a,float b)x=a;y=b;void Point:setPoint(float a,float b)x=a;y=b;ostream & operator(ostream &output,const Point &p)outputp.x,p

39、.y;return output;/第(3)部分/聲明Circle類(lèi)class Circle:public Pointpublic: Circle(float x=0,float y=0,float r=0); void setRadius(float); float getRadius( ) const; virtual float area( ) const; virtual void shapeName( ) const coutCircle:;/對(duì)虛函數(shù)進(jìn)行再定義 friend ostream &operator(ostream &,const Circle &);protected:

40、第46頁(yè)/共55頁(yè) float radius;/聲明Circle類(lèi)成員函數(shù)Circle:Circle(float a,float b,float r):Point(a,b),radius(r) void Circle:setRadius(float r):radius(r) float Circle:getRadius( ) const return radius;float Circle:area( ) const return 3.14159*radius*radius;ostream &operator(ostream &output,const Circle &c)outputc.x,

41、c.y, r=c.radius; return output;第(4)部分/聲明Cylinder類(lèi)class Cylinder:public Circlepublic: Cylinder (float x=0,float y=0,float r=0,float h=0); void setHeight(float); virtual float area( ) const; virtual float volume( ) const;第47頁(yè)/共55頁(yè) virtual void shapeName( ) const coutCylinder:;/對(duì)虛函數(shù)進(jìn)行再定義 friend ostream

42、& operator(ostream&,const Cylinder&); protected: float height; /定義Cylinder類(lèi)成員函數(shù)Cylinder:Cylinder(float a,float b,float r,float h) :Circle(a,b,r),height(h) void Cylinder:setHeight(float h)height=h;float Cylinder:area( ) const return 2*Circle:area( )+2*3.14159*radius*height;float Cylinder:volume( ) co

43、nstreturn Circle:area( )*height;ostream &operator(ostream &output,const Cylinder& cy)outputcy.x,cy.y, r=cy.radius, h=cy.height;return output;第48頁(yè)/共55頁(yè)/main函數(shù)int main( )Point point(3.2,4.5); /建立Point類(lèi)對(duì)象point Circle circle(2.4,1.2,5.6); /建立Circle類(lèi)對(duì)象circle Cylinder cylinder(3.5,6.4,5.2,10.5); /建立Cylind

44、er類(lèi)對(duì)象cylinder point.shapeName(); /靜態(tài)關(guān)聯(lián) coutpointendl; circle.shapeName(); /靜態(tài)關(guān)聯(lián) coutcircleendl; cylinder.shapeName(); /靜態(tài)關(guān)聯(lián) coutcylinderendlshapeName( ); /動(dòng)態(tài)關(guān)聯(lián) coutx=point.getX( ),y=point.getY( )narea=area( ) nvolume=volume()shapeName( ); /動(dòng)態(tài)關(guān)聯(lián) coutx=circle.getX( ),y=circle.getY( )narea=area( ) nvol

45、ume=volume( )shapeName( ); /動(dòng)態(tài)關(guān)聯(lián) coutx=cylinder.getX( ),y=cylinder.getY( )narea=area( )nvolume=volume( )nn; return 0;以上程序也可:先定義函數(shù) void fn( Shape & x) x. shapeName( ); 再 void main( ) fn(point); fn(circle); fn(cylinder); .程序運(yùn)行結(jié)果如下:第50頁(yè)/共55頁(yè)P(yáng) o i n t : 3 . 2 , 4 . 5 ( P o i n t 類(lèi) 對(duì) 象 p o i n t 的 數(shù) 據(jù) :

46、點(diǎn) 的 坐 標(biāo) )C i r c l e : 2 . 4 , 1 . 2 , r = 5 . 6 ( C i r c l e 類(lèi) 對(duì) 象 c i r c l e 的 數(shù) 據(jù) : 圓 心 和 半 徑 )C y l i n d e r : 3 . 5 , 6 . 4 , r = 5 . 5 , h = 1 0 . 5 ( C y l i n d e r 類(lèi) 對(duì) 象 c y l i n d e r 的 數(shù) 據(jù) : 圓 心 、 半 徑 和 高 )P o i n t : x = 3 . 2 , y = 4 . 5 ( 輸 出 P o i n t 類(lèi) 對(duì) 象 p o i n t 的 數(shù) 據(jù) : 點(diǎn) 的 坐

47、 標(biāo) )a r e a = 0 ( 點(diǎn) 的 面 積 )v o l u m e = 0 ( 點(diǎn) 的 體 積 )C i r c l e : x = 2 . 4 , y = 1 . 2 ( 輸 出 C i r c l e 類(lèi) 對(duì) 象 c i r c l e 的 數(shù) 據(jù) : 圓 心 坐 標(biāo) )a r e a = 9 8 . 5 2 0 3 ( 圓 的 面 積 )v o l u m e = 0 ( 圓 的 體 積 )C y l i n d e r : x = 3 . 5 , y = 6 . 4 ( 輸 出 C y l i n d e r 類(lèi) 對(duì) 象 c y l i n d e r 的 數(shù) 據(jù) : 圓 心

48、 坐 標(biāo) )a r e a = 5 1 2 . 5 9 5 ( 圓 的 面 積 )v o l u m e = 8 9 1 . 9 6 ( 圓 柱 的 體 積 ) 第51頁(yè)/共55頁(yè)從本例可以進(jìn)一步明確以下結(jié)論:(1) 一個(gè)基類(lèi)如果包含一個(gè)或一個(gè)以上純虛函數(shù),就是抽象基類(lèi)。抽象基類(lèi)不能也不必要定義對(duì)象。(2) 抽象基類(lèi)與普通基類(lèi)不同,它不是現(xiàn)實(shí)存在的對(duì)象的抽象(例如圓形(Circle)就是千千萬(wàn)萬(wàn)個(gè)實(shí)際的圓的抽象),它可以沒(méi)有任何物理上的或其他實(shí)際意義方面的含義。(3) 在類(lèi)的層次結(jié)構(gòu)中,頂層或最上面的幾層可以是抽象基類(lèi)。抽象基類(lèi)體現(xiàn)了本類(lèi)族中各類(lèi)的共性,把各類(lèi)中共有的成員函數(shù)集中在抽象基類(lèi)中聲

49、明。(4) 抽象基類(lèi)是本類(lèi)族的公共接口?;蛘哒f(shuō),從同一基類(lèi)派生出的多個(gè)類(lèi)有同一接口。 (5) 區(qū)別靜態(tài)關(guān)聯(lián)和動(dòng)態(tài)關(guān)聯(lián)。第52頁(yè)/共55頁(yè)(6) 如果在基類(lèi)聲明了虛函數(shù),則在派生類(lèi)中凡是與該函數(shù)有相同的函數(shù)名、函數(shù)類(lèi)型、參數(shù)個(gè)數(shù)和類(lèi)型的函數(shù),均為虛函數(shù)(不論在派生類(lèi)中是否用virtual聲明)。(7) 使用虛函數(shù)提高了程序的可擴(kuò)充性。把類(lèi)的聲明與類(lèi)的使用分離。這對(duì)于設(shè)計(jì)類(lèi)庫(kù)的軟件開(kāi)發(fā)商來(lái)說(shuō)尤為重要。開(kāi)發(fā)商設(shè)計(jì)了各種各樣的類(lèi),但不向用戶(hù)提供源代碼,用戶(hù)可以不知道類(lèi)是怎樣聲明的,但是可以使用這些類(lèi)來(lái)派生出自己的類(lèi)。利用虛函數(shù)和多態(tài)性,程序員的注意力集中在處理普遍性,而讓執(zhí)行環(huán)境處理特殊性。第53頁(yè)/共55頁(yè)虛基類(lèi)與抽象基類(lèi)的區(qū)別:前者解決模糊二義性問(wèn)題;后者解決繼承中的多態(tài)性問(wèn)題。實(shí)現(xiàn)時(shí),前者由在繼承方式前加virtual; 后者靠純虛函數(shù)實(shí)現(xiàn)。虛函數(shù)與純虛函數(shù)對(duì)比:純?cè)诔橄箢?lèi)中,被“初始化”為0的函數(shù)。沒(méi)有實(shí)際意義,為派生類(lèi)保留名字,方便該函數(shù)實(shí)現(xiàn)多態(tài)性。虛函數(shù)有實(shí)際意義,也是為實(shí)現(xiàn)多態(tài)性服務(wù)。第54頁(yè)/共55頁(yè)感謝您的觀看!第55頁(yè)/共55頁(yè)

展開(kāi)閱讀全文
溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

相關(guān)資源

更多
正為您匹配相似的精品文檔
關(guān)于我們 - 網(wǎng)站聲明 - 網(wǎng)站地圖 - 資源地圖 - 友情鏈接 - 網(wǎng)站客服 - 聯(lián)系我們

copyright@ 2023-2025  zhuangpeitu.com 裝配圖網(wǎng)版權(quán)所有   聯(lián)系電話(huà):18123376007

備案號(hào):ICP2024067431號(hào)-1 川公網(wǎng)安備51140202000466號(hào)


本站為文檔C2C交易模式,即用戶(hù)上傳的文檔直接被用戶(hù)下載,本站只是中間服務(wù)平臺(tái),本站所有文檔下載所得的收益歸上傳人(含作者)所有。裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)上載內(nèi)容本身不做任何修改或編輯。若文檔所含內(nèi)容侵犯了您的版權(quán)或隱私,請(qǐng)立即通知裝配圖網(wǎng),我們立即給予刪除!