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

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

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

20 積分

下載資源

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

資源描述:

《譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件》由會(huì)員分享,可在線閱讀,更多相關(guān)《譚浩強(qiáng)C程序設(shè)計(jì) nPPT課件(55頁珍藏版)》請(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)生不同的行為(即方法)。也就是說,每個(gè)對(duì)象可以用自己的方式去響應(yīng)共同的消息。12.1 多態(tài)性的概念第1頁/共55頁優(yōu)點(diǎn):在C+程序設(shè)計(jì)中,在不同的類中定義了其響應(yīng)消息的方法,那么使用這些類時(shí),不必考慮它們是什么類型,只要發(fā)布消息即可。多態(tà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)性又稱編譯時(shí)的多態(tài)性。p動(dòng)態(tài)多態(tài)性:是在程序運(yùn)行過程中才動(dòng)態(tài)地確定操作所針對(duì)的對(duì)象。它又稱運(yùn)行時(shí)的多態(tài)性。動(dòng)態(tài)多態(tài)性是通過虛函數(shù)(virtual function)實(shí)現(xiàn)的。在本章中主要介紹動(dòng)態(tài)多態(tài)性和虛函數(shù)。第2頁/共55頁下面是一個(gè)承上啟下的例子。一方面它是有關(guān)繼承和運(yùn)算符重載內(nèi)容的綜合應(yīng)用的例子,通過這個(gè)例子可以進(jìn)一步融會(huì)貫通前面所學(xué)的內(nèi)容,另一方面又是作為討論多態(tài)性的一個(gè)基礎(chǔ)用例。12.2 一個(gè)典型的例子第3頁/共55頁例12.1 先建立一個(gè)Point(點(diǎn))類,包含數(shù)據(jù)成員x,y(坐標(biāo)點(diǎn))。以它為

3、基類,派生出一個(gè)Circle(圓)類,增加數(shù)據(jù)成員r(半徑),再以Circle類為直接基類,派生出一個(gè)Cylinder(圓柱體)類,再增加數(shù)據(jù)成員h(高)。要求編寫程序,重載運(yùn)算符“”,使之能用于輸出以上類對(duì)象。對(duì)于一個(gè)比較大的程序,應(yīng)當(dāng)分成若干步驟進(jìn)行。先聲明基類,再聲明派生類,逐級(jí)進(jìn)行,分步調(diào)試。(1) 聲明基類Point類 寫出聲明基類Point的部分:#include /聲明類Point /聲明一個(gè)類包括什么?class Pointpublic: Point(float x=0,float y=0);/有默認(rèn)參數(shù)的構(gòu)造函數(shù)第4頁/共55頁 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類的成員函數(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;以上完成了基類Point類的聲明。第5頁/共55頁現(xiàn)在要對(duì)上面寫的基類聲明進(jìn)行調(diào)試,檢查它是否有錯(cuò),為此要寫出main函數(shù)。實(shí)際上它是一個(gè)測(cè)試程序。int main( )Point p(3.5,6.4);/建立Point類對(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)程序編譯通過,運(yùn)行結(jié)果為x=3.5,y=6.4p(new):8.5,6.8測(cè)試程序檢查了基類中各函數(shù)的功能,以及運(yùn)算符重載的作用,證明程序是正確的。第6頁/共55頁(2) 聲明派生類Circleclass Circle:public Point/circle是Point類的公用派生類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頁/共55頁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類的定義,可以寫出下面的主函數(shù):第8頁/共55頁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 類 對(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 類 的 引 用 變 量 , 被 c 初 始 化 c o u t p R e f : p R e f ; / / 輸 出 p R e f 的 信 息 r e t u r n 0 ;程 序 編 譯 通 過 , 運(yùn) 行 結(jié) 果 為 o r i g i n a l c i r c l e : ( 輸 出 原 來 的 圓 的 數(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頁/共55頁(3) 聲明Circle的派生類Cylinderclass Cylinder:public Circle/ Cylinder是Circle的公用派生類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頁/共55頁/計(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頁/共55頁 可以寫出下面的主函數(shù): int main( )Cylinder cy1(3.5,6.4,5.2,10);/定義Cylinder類對(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類對(duì)象的引用變量第12頁/共55頁 coutnpRef as a Poi

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

17、序中Student是基類,Graduate是派生類,它們都有display這個(gè)同名的函數(shù)。#include #include using namespace std;/聲明基類Studentclass Studentpublic: Student(int, string,float);/聲明構(gòu)造函數(shù) void display( ); /聲明輸出函數(shù) protected: /受保護(hù)成員,派生類可以訪問 int num; string name; float score; ;第16頁/共55頁 /Student類成員函數(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頁/共55頁/聲明公用派生類Graduateclass Graduate:public Studentpublic: Graduate(int, string, float, float); /聲明構(gòu)造函數(shù) void display( ); /聲明輸出函數(shù)private: float pay;/ Graduate類成員函數(shù)的實(shí)現(xiàn)void Graduate:display( ) /定

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

20、ent類的display函數(shù)聲明為虛函數(shù)。程序其他部分都不改動(dòng)。再編譯和運(yùn)行程序,請(qǐng)注意分析運(yùn)行結(jié)果: 第20頁/共55頁num:1001(stud1的數(shù)據(jù))name:Liscore:87.5num:2001 (grad1中基類部分的數(shù)據(jù),達(dá)到目的!)name:wangscore:98.5pay=1200 (這一項(xiàng)以前是沒有的)由虛函數(shù)實(shí)現(xiàn)的動(dòng)態(tài)多態(tà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頁/共55頁虛函數(shù)的使用方法是: 注意規(guī)則! (1) 在基

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

22、數(shù)。(3) 必須定義一個(gè)指向基類對(duì)象的指針變量,并使它指向同一類族中需要調(diào)用該函數(shù)的對(duì)象。(4) 通過該指針變量調(diào)用此虛函數(shù),此時(shí)調(diào)用的就是指針變量指向的對(duì)象的同名函數(shù)。第23頁/共55頁舉例2 :用引用也可,如將上面例題改為void fun( Student & x)/必須為基類指針或引用! 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頁/共55頁顯示結(jié)果:num:1001(stud1的數(shù)據(jù))

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

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

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

26、2) 應(yīng)考慮對(duì)成員函數(shù)的調(diào)用是通過對(duì)象名還是通過基類指針或引用去訪問,如果是通過基類指針或引用去訪問的,則應(yīng)當(dāng)聲明為虛函數(shù)。需要說明的是: 使用虛函數(shù),系統(tǒng)要有一定的空間開銷。當(dāng)一個(gè)類帶有虛函數(shù)時(shí),編譯系統(tǒng)會(huì)為該類構(gòu)造一個(gè)虛函數(shù)表(virtual function table,簡(jiǎn)稱vtable),它是一個(gè)指針數(shù)組,存放每個(gè)虛函數(shù)的入口地址。系統(tǒng)在進(jìn)行動(dòng)態(tài)關(guān)聯(lián)時(shí)的時(shí)間開銷是很少的,因此,多態(tài)性是高效的。第31頁/共55頁多態(tài)性進(jìn)一步理解:多態(tài)性是指在運(yùn)行時(shí),能根據(jù)其類型確認(rèn)調(diào)用哪個(gè)函數(shù)的能力。只支持類而不支持多態(tài),稱基于對(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è)類型的收費(fèi)員(函數(shù))去收費(fèi)。 希望只有一個(gè)收費(fèi)員void fn(Student &x) x.calcTuition();若不這樣, fn中要判斷,分別調(diào)用,維護(hù)量大,面向?qū)ο髢?yōu)越性被限制,又回到面向過程。 第32頁/共55頁析構(gòu)函數(shù)的作用是在對(duì)象撤銷之前做必要的“清理現(xiàn)場(chǎng)”的工作。當(dāng)派生類的對(duì)象從內(nèi)存中撤銷時(shí)一般先調(diào)用派生類的析構(gòu)函數(shù),然后再調(diào)用基類的析構(gòu)函數(shù)。但用delete 刪除對(duì)象時(shí)存在如下問題,即沒有達(dá)到期望的目標(biāo)。如何解決?

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

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

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

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

32、,一個(gè)是求圓面積,一個(gè)是求圓柱體表面積。僅供派生而無實(shí)際意義的函數(shù),故純虛之。12.4 純虛函數(shù)與抽象類 12.4.1 純虛函數(shù)第38頁/共55頁有的讀者自然會(huì)想到,在這種情況下應(yīng)當(dāng)將area聲明為虛函數(shù)??梢栽诨怭oint中加一個(gè)area函數(shù),并聲明為虛函數(shù): virtual float area( ) const return 0;其返回值為0,表示“點(diǎn)”是沒有面積的。為簡(jiǎn)化,可以不寫出這種無意義的函數(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ù)類型 函數(shù)名 (參數(shù)表列) =0;第39頁/共55頁注意: 純虛函數(shù)沒有函數(shù)體;最后面的“=0”并不表示函數(shù)返回值為0,告訴編譯系統(tǒng)“這是純虛函數(shù)”; 這是一個(gè)聲明語句,最后應(yīng)有分號(hào)。純虛函數(shù)的作用:純虛函數(shù)只有函數(shù)的名字而不具備函數(shù)的功能。它只是通知編譯系統(tǒng): “在這里聲明一個(gè)虛函數(shù),留待派生類中定義”。純虛函數(shù)的作用是在基類中為其派生類保留一個(gè)函數(shù)的名字,以便派生類根據(jù)需要對(duì)它進(jìn)行定義。如果在基類中沒有保留函數(shù)名字,則無法實(shí)現(xiàn)多態(tài)性。如果在一個(gè)類中聲明了純虛函數(shù),而在其派生類中沒有對(duì)該函數(shù)

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

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

36、頁/共55頁例12.4 虛函數(shù)和抽象基類的應(yīng)用。在本章例12.1介紹了以Point為基類的點(diǎn)圓圓柱體類的層次結(jié)構(gòu)?,F(xiàn)在要對(duì)它進(jìn)行改寫,在程序中使用虛函數(shù)和抽象基類。類的層次結(jié)構(gòu)的頂層是抽象基類Shape(形狀)。Point(點(diǎn)), Circle(圓), Cylinder(圓柱體)都是Shape類的直接派生類和間接派生類。下面是一個(gè)完整的程序,為了便于閱讀,分段插入了一些文字說明。程序如下: 12.4.3 應(yīng)用實(shí)例第44頁/共55頁第(1)部分#include using namespace std;/ /聲明抽象基類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類class Point:public Shape/Point是Shape的公用派生類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頁/共55頁 ; 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類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頁/共55頁 float radius;/聲明Circle類成員函數(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類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頁/共55頁 virtual void shapeName( ) const coutCylinder:;/對(duì)虛函數(shù)進(jìn)行再定義 friend ostream

42、& operator(ostream&,const Cylinder&); protected: float height; /定義Cylinder類成員函數(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頁/共55頁/main函數(shù)int main( )Point point(3.2,4.5); /建立Point類對(duì)象point Circle circle(2.4,1.2,5.6); /建立Circle類對(duì)象circle Cylinder cylinder(3.5,6.4,5.2,10.5); /建立Cylind

44、er類對(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頁/共55頁P(yáng) o i n t : 3 . 2 , 4 . 5 ( P o i n t 類 對(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 類 對(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 類 對(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 類 對(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 類 對(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 類 對(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頁/共55頁從本例可以進(jìn)一步明確以下結(jié)論:(1) 一個(gè)基類如果包含一個(gè)或一個(gè)以上純虛函數(shù),就是抽象基類。抽象基類不能也不必要定義對(duì)象。(2) 抽象基類與普通基類不同,它不是現(xiàn)實(shí)存在的對(duì)象的抽象(例如圓形(Circle)就是千千萬萬個(gè)實(shí)際的圓的抽象),它可以沒有任何物理上的或其他實(shí)際意義方面的含義。(3) 在類的層次結(jié)構(gòu)中,頂層或最上面的幾層可以是抽象基類。抽象基類體現(xiàn)了本類族中各類的共性,把各類中共有的成員函數(shù)集中在抽象基類中聲

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

展開閱讀全文
溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(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ì)自己和他人造成任何形式的傷害或損失。

相關(guān)資源

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

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

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


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