譚浩強C程序設計 nPPT課件
《譚浩強C程序設計 nPPT課件》由會員分享,可在線閱讀,更多相關《譚浩強C程序設計 nPPT課件(55頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1、多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O計的一個重要特征。利用多態(tài)性可以設計和實現(xiàn)一個易于擴展的系統(tǒng)。p在C+程序設計中,多態(tài)性是指具有不同功能的函數(shù)可以用同一個函數(shù)名,這樣就可以用一個函數(shù)名調(diào)用不同內(nèi)容的函數(shù)。p在面向?qū)ο蠓椒ㄖ械亩鄳B(tài)性: 向不同的對象發(fā)送同一個消息(函數(shù)名),不同的對象在接收時會產(chǎn)生不同的行為(即方法)。也就是說,每個對象可以用自己的方式去響應共同的消息。12.1 多態(tài)性的概念第1頁/共55頁優(yōu)點:在C+程序設計中,在不同的類中定義了其響應消息的方法,那么使用這些類時,不必考慮它們是什么類型,只要發(fā)布消息即可。多態(tài)性分為兩類: 靜態(tài)多態(tài)性和動態(tài)多態(tài)性。p靜態(tài)多態(tài)性
2、:函數(shù)重載和運算符重載屬于靜態(tài)多態(tài)性,在程序編譯時系統(tǒng)就能決定調(diào)用的是哪個函數(shù),因此靜態(tài)多態(tài)性又稱編譯時的多態(tài)性。p動態(tài)多態(tài)性:是在程序運行過程中才動態(tài)地確定操作所針對的對象。它又稱運行時的多態(tài)性。動態(tài)多態(tài)性是通過虛函數(shù)(virtual function)實現(xiàn)的。在本章中主要介紹動態(tài)多態(tài)性和虛函數(shù)。第2頁/共55頁下面是一個承上啟下的例子。一方面它是有關繼承和運算符重載內(nèi)容的綜合應用的例子,通過這個例子可以進一步融會貫通前面所學的內(nèi)容,另一方面又是作為討論多態(tài)性的一個基礎用例。12.2 一個典型的例子第3頁/共55頁例12.1 先建立一個Point(點)類,包含數(shù)據(jù)成員x,y(坐標點)。以它為
3、基類,派生出一個Circle(圓)類,增加數(shù)據(jù)成員r(半徑),再以Circle類為直接基類,派生出一個Cylinder(圓柱體)類,再增加數(shù)據(jù)成員h(高)。要求編寫程序,重載運算符“”,使之能用于輸出以上類對象。對于一個比較大的程序,應當分成若干步驟進行。先聲明基類,再聲明派生類,逐級進行,分步調(diào)試。(1) 聲明基類Point類 寫出聲明基類Point的部分:#include /聲明類Point /聲明一個類包括什么?class Pointpublic: Point(float x=0,float y=0);/有默認參數(shù)的構(gòu)造函數(shù)第4頁/共55頁 void setPoint(float,flo
4、at); /設置坐標值 float getX( ) const return x; /讀x坐標 float getY( ) const return y; /讀y坐標 friend ostream & operator(ostream &,const Point &);/重載運算符“”protected: /受保護成員 float x,y;/下面定義Point類的成員函數(shù) /Point的構(gòu)造函數(shù)Point:Point(float a,float b) /對x,y初始化x=a;y=b;/設置x和y的坐標值void Point:setPoint(float a,float b) /為x,y賦新值x
5、=a;y=b;/重載運算符“”,使之能輸出點的坐標ostream & operator(ostream &output,const Point &p)outputp.x,p.yendl; return output;以上完成了基類Point類的聲明。第5頁/共55頁現(xiàn)在要對上面寫的基類聲明進行調(diào)試,檢查它是否有錯,為此要寫出main函數(shù)。實際上它是一個測試程序。int main( )Point p(3.5,6.4);/建立Point類對象p coutx=p.getX( ),y=p.getY( )endl;/輸出p的坐標值 p.setPoint(8.5,6.8); /重新設置p的坐標值 cout
6、p(new):pendl; /用重載運算符“”輸出p點坐標程序編譯通過,運行結(jié)果為x=3.5,y=6.4p(new):8.5,6.8測試程序檢查了基類中各函數(shù)的功能,以及運算符重載的作用,證明程序是正確的。第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); /設置半徑值 float getRadius( ) const; /讀取半徑值 float area (
7、) const; /計算圓面積 friend ostream &operator(ostream &,const Circle &);/重載運算符“” private:/?protected: float radius;/定義構(gòu)造函數(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
8、:area( ) const第7頁/共55頁return 3.14159*radius*radius;/重載運算符“”,使之按規(guī)定的形式輸出圓的信息ostream &operator(ostream &output,const Circle &c)outputCenter=c.x,c.y,r=c.radius,area=c.area( )endl; return output;為了測試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 類 對 象 c , 并 給 定 圓 心 坐 標 和 半 徑 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 ; / / 輸 出 圓 心 坐 標 、 半 徑 和 面 積 c . s e t R a d i u s ( 7 . 5 ) ; / / 設 置 半 徑 值 c . s e t P o i n t ( 5 , 5 ) ; / / 設
10、置 圓 心 坐 標 值 x , y c o u t n e w c i r c l e : n c ; / / 用 重 載 運 算 符 “ ” 輸 出 圓 對 象 的 信 息 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 ;程 序 編 譯 通 過 , 運 行 結(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 ( 輸 出 圓 的 圓 心 “ 點 ” 的 數(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); /設置圓柱高 float getHeight( ) const; /讀取圓柱高 float area( ) const; /計算圓表面積 float volume( ) const; /計算圓柱體積 friend ostream& operator(ostream&,const Cylinder&);/重載運算符“” 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; /設置圓柱高float Cylinder:getHeight( ) const return height; /讀取圓柱高第10頁/共55頁/計算圓表面積float Cylinder:area( ) const return 2*Circle:area( )+2*3.14159*radius*height;float Cylinder:volume() const/計算圓柱體積return Circle:area()
14、*height;/重載運算符“”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類對象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)定義的運算符“”輸出cy1的數(shù)據(jù) cy1.setHeight(15); /設置圓柱高 cy1.setRadius(7.5); /設置圓半徑 cy1.setPoint(5,5); /設置圓心坐標值x,y coutnnew cylinder:ncy1; /用重載運算符“”輸出cy1的數(shù)據(jù) Point &pRef=cy1; /pRef是Point類對象的引用變量第12頁/共55頁 coutnpRef as a Poi
16、nt:pRef; /pRef作為一個“點”輸出 Circle &cRef=cy1; /cRef是Circle類對象的引用變量 coutncRef as a Circle:display( );”可以調(diào)用不同派生層次中的display函數(shù),只需在調(diào)用前給指針變量pt賦以不同的值(使之指向不同的類對象)即可。C+中的虛函數(shù)就是用來解決這個問題的。虛函數(shù)的作用是允許在派生類中重新定義與基類同名的函數(shù),并且可以通過基類指針或引用來訪問基類和派生類中的同名函數(shù)。方法:由基類指針,訪問各層次中的同名函數(shù)。例12.2。再討論使用虛函數(shù)的情況。第15頁/共55頁例12.2 基類與派生類中有同名函數(shù)。在下面的程
17、序中Student是基類,Graduate是派生類,它們都有display這個同名的函數(shù)。#include #include using namespace std;/聲明基類Studentclass Studentpublic: Student(int, string,float);/聲明構(gòu)造函數(shù) void display( ); /聲明輸出函數(shù) protected: /受保護成員,派生類可以訪問 int num; string name; float score; ;第16頁/共55頁 /Student類成員函數(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ù)的實現(xiàn)void Graduate:display( ) /定
19、義輸出函數(shù) coutnum:numnname:namenscore:scorenpay=paydisplay( ); pt=&grad1; pt-display( ); return 0; 第19頁/共55頁運行結(jié)果如下,請仔細分析。num:1001(stud1的數(shù)據(jù))name:Liscore:87.5num:2001 (僅輸出了grad1中基類部分的數(shù)據(jù),沒實現(xiàn)多態(tài)性!)name:wangscore:98.5下面對程序作一點修改,在Student類中聲明display函數(shù)時,在最左面加一個關鍵字virtual,即virtual void display( );變成虛函數(shù)就行了這樣就把Stud
20、ent類的display函數(shù)聲明為虛函數(shù)。程序其他部分都不改動。再編譯和運行程序,請注意分析運行結(jié)果: 第20頁/共55頁num:1001(stud1的數(shù)據(jù))name:Liscore:87.5num:2001 (grad1中基類部分的數(shù)據(jù),達到目的!)name:wangscore:98.5pay=1200 (這一項以前是沒有的)由虛函數(shù)實現(xiàn)的動態(tài)多態(tài)性就是: 同一類族中不同類的對象,對同一函數(shù)調(diào)用作出不同的響應。多態(tài)性理解:起始地址相同的不同對象指針,調(diào)同名函數(shù)時,響應不同(調(diào)了各自對應的函數(shù))。實現(xiàn)方法:將同名函數(shù)聲明為虛函數(shù)。第21頁/共55頁虛函數(shù)的使用方法是: 注意規(guī)則! (1) 在基
21、類用virtual聲明成員函數(shù)為虛函數(shù)。這樣就可以在派生類中重新定義此函數(shù),為它賦予新的功能,并能方便地被調(diào)用。 在類外定義虛函數(shù)時,不必再加virtual。(2) 在派生類中重新定義此函數(shù),要求函數(shù)名、函數(shù)類型、函數(shù)參數(shù)個數(shù)和類型全部與基類的虛函數(shù)相同,并根據(jù)派生類的需要重新定義函數(shù)體。 第22頁/共55頁C+規(guī)定,當一個成員函數(shù)被聲明為虛函數(shù)后,其派生類中的同名函數(shù)都自動成為虛函數(shù)。因此在派生類重新聲明該虛函數(shù)時,可以加virtual,也可以不加,但習慣上一般在每一層聲明該函數(shù)時都加virtual,使程序更加清晰。如果在派生類中沒有對基類的虛函數(shù)重新定義,則派生類簡單地繼承其直接基類的虛函
22、數(shù)。(3) 必須定義一個指向基類對象的指針變量,并使它指向同一類族中需要調(diào)用該函數(shù)的對象。(4) 通過該指針變量調(diào)用此虛函數(shù),此時調(diào)用的就是指針變量指向的對象的同名函數(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ù)或類型不同)。第26頁/共55頁這樣編譯系統(tǒng)在對程序進行編譯時,即能確定調(diào)用的是哪個類對象中的函數(shù)。確定調(diào)用的具體對象的過程稱為關聯(lián)(binding)。在這里是指把一個函數(shù)名與一個類對象捆綁在一起,建立關聯(lián)。一般地說,關聯(lián)指把
24、一個標識符和一個存儲地址聯(lián)系起來。12.3.2 靜態(tài)關聯(lián)與動態(tài)關聯(lián) 第27頁/共55頁函數(shù)重載和通過對象名調(diào)用的虛函數(shù),在編譯時即可確定其調(diào)用的虛函數(shù)屬于哪一個類,其過程稱為靜態(tài)關聯(lián)(static binding),由于是在運行前進行關聯(lián)的,故又稱為早期關聯(lián)(early binding)。函數(shù)重載屬靜態(tài)關聯(lián)。 而運行時的多態(tài)性,編譯系統(tǒng)在編譯該行時是無法確定調(diào)用哪一個類對象的虛函數(shù)的。因為編譯只作靜態(tài)的語法檢查,光從語句形式是無法確定調(diào)用對象的。第28頁/共55頁例如,先使pt指向grad1,再執(zhí)行“pt-display( )”,當然是調(diào)用grad1中的display函數(shù)。由于是在運行階段把虛
25、函數(shù)和類對象“綁定”在一起的,因此,此過程稱為動態(tài)關聯(lián)(dynamic binding)。這種多態(tài)性是動態(tài)的多態(tài)性,即運行階段的多態(tài)性。在運行階段,指針可以先后指向不同的類對象,從而調(diào)用同一類族中不同類的虛函數(shù)。由于動態(tài)關聯(lián)是在編譯以后的運行階段進行的,因此也稱為滯后關聯(lián)(late binding)。第29頁/共55頁使用虛函數(shù)時,有兩點要注意: (1)只能用virtual聲明類的成員函數(shù),使它成為虛函數(shù),而不能將類外的普通函數(shù)聲明為虛函數(shù)。因為虛函數(shù)的作用:是允許在派生類中對基類的虛函數(shù)重新定義。顯然,它只能用于類的繼承層次結(jié)構(gòu)中。12.3.3 在什么情況下應當聲明虛函數(shù)第30頁/共55頁(
26、2) 應考慮對成員函數(shù)的調(diào)用是通過對象名還是通過基類指針或引用去訪問,如果是通過基類指針或引用去訪問的,則應當聲明為虛函數(shù)。需要說明的是: 使用虛函數(shù),系統(tǒng)要有一定的空間開銷。當一個類帶有虛函數(shù)時,編譯系統(tǒng)會為該類構(gòu)造一個虛函數(shù)表(virtual function table,簡稱vtable),它是一個指針數(shù)組,存放每個虛函數(shù)的入口地址。系統(tǒng)在進行動態(tài)關聯(lián)時的時間開銷是很少的,因此,多態(tài)性是高效的。第31頁/共55頁多態(tài)性進一步理解:多態(tài)性是指在運行時,能根據(jù)其類型確認調(diào)用哪個函數(shù)的能力。只支持類而不支持多態(tài),稱基于對象的;如VB。只有支持多態(tài),才成為面向?qū)ο蟮?。好處分析:如計算學生的學費,
27、有大學生,研究生,博士生等。從程序設計看,用采取繼承方式設計。希望只有一個收費員(函數(shù))可以收各種學生的費用。 而不是首先有一個管理者判斷是什么學生?再分派給各個類型的收費員(函數(shù))去收費。 希望只有一個收費員void fn(Student &x) x.calcTuition();若不這樣, fn中要判斷,分別調(diào)用,維護量大,面向?qū)ο髢?yōu)越性被限制,又回到面向過程。 第32頁/共55頁析構(gòu)函數(shù)的作用是在對象撤銷之前做必要的“清理現(xiàn)場”的工作。當派生類的對象從內(nèi)存中撤銷時一般先調(diào)用派生類的析構(gòu)函數(shù),然后再調(diào)用基類的析構(gòu)函數(shù)。但用delete 刪除對象時存在如下問題,即沒有達到期望的目標。如何解決?
28、12.3.4 虛析構(gòu)函數(shù)(還有什么函數(shù)可以虛之?)(還有什么函數(shù)可以虛之?)第33頁/共55頁例12.3 基類中有非虛析構(gòu)函數(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開辟動態(tài)存儲空間delete p; /用delete釋放動態(tài)存儲空間return 0;這只是一個示意的程序。p是指向基類的指針變量,指向new開辟的動態(tài)存儲空間,希望用detele釋放p所指向的空間,即元類對象的空間。但運行結(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;程序其他部分不改動,再運行程序,結(jié)果為executing Circle destructorexecuting Point destructor先調(diào)用了派生類的析構(gòu)函數(shù),再調(diào)用了基類的析構(gòu)函數(shù),符合人們的愿望。第36頁/共55頁特點與好處:如果將基類的析構(gòu)函數(shù)聲明為虛函數(shù)時,由該基類所派生的所有派生類的析構(gòu)函數(shù)也都自動成為虛函數(shù)。這樣,如果程序中顯式地用了delete運算符準備刪除一個對象,而delete運算符的操作對象用
31、了指向派生類對象的基類指針,則系統(tǒng)會調(diào)用相應類的析構(gòu)函數(shù)。一般即使基類并不需要析構(gòu)函數(shù),也顯式地定義一個函數(shù)體為空的虛析構(gòu)函數(shù),以保證在撤銷動態(tài)分配空間時能得到正確的處理。構(gòu)造函數(shù)不能聲明為虛函數(shù)。這是因為在執(zhí)行構(gòu)造函數(shù)時類對象還未完成建立過程,當然談不上函數(shù)與類對象的綁定。第37頁/共55頁例如在本章的例12.1程序中,基類Point中沒有求面積的area函數(shù),因為“點”是沒有面積的,也就是說,基類本身不需要這個函數(shù),所以在例12.1程序中的Point類中沒有定義area函數(shù)。但是,在其直接派生類Circle和間接派生類Cylinder中都需要有area函數(shù),而且這兩個area函數(shù)的功能不同
32、,一個是求圓面積,一個是求圓柱體表面積。僅供派生而無實際意義的函數(shù),故純虛之。12.4 純虛函數(shù)與抽象類 12.4.1 純虛函數(shù)第38頁/共55頁有的讀者自然會想到,在這種情況下應當將area聲明為虛函數(shù)??梢栽诨怭oint中加一個area函數(shù),并聲明為虛函數(shù): virtual float area( ) const return 0;其返回值為0,表示“點”是沒有面積的。為簡化,可以不寫出這種無意義的函數(shù)體,只給出函數(shù)的原型,并在后面加上“=0”,如virtual float area( ) const =0;/純虛函數(shù)這就將area聲明為一個純虛函數(shù)(pure virtual funct
33、ion)。純虛函數(shù)是在聲明虛函數(shù)時被“初始化”為0的函數(shù)。聲明純虛函數(shù)的一般形式是virtual 函數(shù)類型 函數(shù)名 (參數(shù)表列) =0;第39頁/共55頁注意: 純虛函數(shù)沒有函數(shù)體;最后面的“=0”并不表示函數(shù)返回值為0,告訴編譯系統(tǒng)“這是純虛函數(shù)”; 這是一個聲明語句,最后應有分號。純虛函數(shù)的作用:純虛函數(shù)只有函數(shù)的名字而不具備函數(shù)的功能。它只是通知編譯系統(tǒng): “在這里聲明一個虛函數(shù),留待派生類中定義”。純虛函數(shù)的作用是在基類中為其派生類保留一個函數(shù)的名字,以便派生類根據(jù)需要對它進行定義。如果在基類中沒有保留函數(shù)名字,則無法實現(xiàn)多態(tài)性。如果在一個類中聲明了純虛函數(shù),而在其派生類中沒有對該函數(shù)
34、定義,則該虛函數(shù)在派生類中仍然為純虛函數(shù)。第40頁/共55頁如果聲明了一個類,一般可以用它定義對象。但是在面向?qū)ο蟪绦蛟O計中,往往有一些類,它們不用來生成對象。定義這些類的惟一目的是用它作為基類去建立派生類。這種不用來定義對象而只作為一種基本類型用作繼承的類,稱為抽象類(abstract class),由于它常用作基類,通常稱為抽象基類(abstract base class)。12.4.2 抽象類第41頁/共55頁凡是包含純虛函數(shù)的類都是抽象類。因為純虛函數(shù)是不能被調(diào)用的,包含純虛函數(shù)的類是無法建立對象的。抽象類的作用是作為一個類族的共同基類,或者說,為一個類族提供一個公共接口。抽象類的條件
35、:包含純虛函數(shù)使用規(guī)則:如果在抽象類所派生出的新類中對基類的所有純虛函數(shù)進行了定義,那么這些函數(shù)就被賦予了功能,可以被調(diào)用。這個派生類就不是抽象類,而是可以用來定義對象的具體類(concrete class)。如果在派生類中沒有對所有純虛函數(shù)進行定義,則此派生類仍然是抽象類,不能用來定義對象。第42頁/共55頁雖然抽象類不能定義對象(或者說抽象類不能實例化),但是可以定義指向抽象類數(shù)據(jù)的指針變量。當派生類成為具體類之后,就可以用這種指針指向派生類對象,然后通過該指針調(diào)用虛函數(shù),實現(xiàn)多態(tài)性的操作??偨Y(jié):抽象類的實際作用:定義指向抽象類的指針,實現(xiàn)多態(tài)性操作。即對各純虛函數(shù)可實現(xiàn)多態(tài)性操作。第43
36、頁/共55頁例12.4 虛函數(shù)和抽象基類的應用。在本章例12.1介紹了以Point為基類的點圓圓柱體類的層次結(jié)構(gòu)?,F(xiàn)在要對它進行改寫,在程序中使用虛函數(shù)和抽象基類。類的層次結(jié)構(gòu)的頂層是抽象基類Shape(形狀)。Point(點), Circle(圓), Cylinder(圓柱體)都是Shape類的直接派生類和間接派生類。下面是一個完整的程序,為了便于閱讀,分段插入了一些文字說明。程序如下: 12.4.3 應用實例第44頁/共55頁第(1)部分#include using namespace std;/ /聲明抽象基類Shape 因含純虛函數(shù)!class Shape /目的:可使各純虛函數(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:; /對虛函數(shù)進行再定義 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:;/對虛函數(shù)進行再定義 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:;/對虛函數(shù)進行再定義 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類對象point Circle circle(2.4,1.2,5.6); /建立Circle類對象circle Cylinder cylinder(3.5,6.4,5.2,10.5); /建立Cylind
44、er類對象cylinder point.shapeName(); /靜態(tài)關聯(lián) coutpointendl; circle.shapeName(); /靜態(tài)關聯(lián) coutcircleendl; cylinder.shapeName(); /靜態(tài)關聯(lián) coutcylinderendlshapeName( ); /動態(tài)關聯(lián) coutx=point.getX( ),y=point.getY( )narea=area( ) nvolume=volume()shapeName( ); /動態(tài)關聯(lián) coutx=circle.getX( ),y=circle.getY( )narea=area( ) nvol
45、ume=volume( )shapeName( ); /動態(tài)關聯(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); .程序運行結(jié)果如下:第50頁/共55頁P o i n t : 3 . 2 , 4 . 5 ( P o i n t 類 對 象 p o i n t 的 數(shù) 據(jù) :
46、點 的 坐 標 )C i r c l e : 2 . 4 , 1 . 2 , r = 5 . 6 ( C i r c l e 類 對 象 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 類 對 象 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 類 對 象 p o i n t 的 數(shù) 據(jù) : 點 的 坐
47、 標 )a r e a = 0 ( 點 的 面 積 )v o l u m e = 0 ( 點 的 體 積 )C i r c l e : x = 2 . 4 , y = 1 . 2 ( 輸 出 C i r c l e 類 對 象 c i r c l e 的 數(shù) 據(jù) : 圓 心 坐 標 )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 類 對 象 c y l i n d e r 的 數(shù) 據(jù) : 圓 心
48、 坐 標 )a r e a = 5 1 2 . 5 9 5 ( 圓 的 面 積 )v o l u m e = 8 9 1 . 9 6 ( 圓 柱 的 體 積 ) 第51頁/共55頁從本例可以進一步明確以下結(jié)論:(1) 一個基類如果包含一個或一個以上純虛函數(shù),就是抽象基類。抽象基類不能也不必要定義對象。(2) 抽象基類與普通基類不同,它不是現(xiàn)實存在的對象的抽象(例如圓形(Circle)就是千千萬萬個實際的圓的抽象),它可以沒有任何物理上的或其他實際意義方面的含義。(3) 在類的層次結(jié)構(gòu)中,頂層或最上面的幾層可以是抽象基類。抽象基類體現(xiàn)了本類族中各類的共性,把各類中共有的成員函數(shù)集中在抽象基類中聲
49、明。(4) 抽象基類是本類族的公共接口?;蛘哒f,從同一基類派生出的多個類有同一接口。 (5) 區(qū)別靜態(tài)關聯(lián)和動態(tài)關聯(lián)。第52頁/共55頁(6) 如果在基類聲明了虛函數(shù),則在派生類中凡是與該函數(shù)有相同的函數(shù)名、函數(shù)類型、參數(shù)個數(shù)和類型的函數(shù),均為虛函數(shù)(不論在派生類中是否用virtual聲明)。(7) 使用虛函數(shù)提高了程序的可擴充性。把類的聲明與類的使用分離。這對于設計類庫的軟件開發(fā)商來說尤為重要。開發(fā)商設計了各種各樣的類,但不向用戶提供源代碼,用戶可以不知道類是怎樣聲明的,但是可以使用這些類來派生出自己的類。利用虛函數(shù)和多態(tài)性,程序員的注意力集中在處理普遍性,而讓執(zhí)行環(huán)境處理特殊性。第53頁/共55頁虛基類與抽象基類的區(qū)別:前者解決模糊二義性問題;后者解決繼承中的多態(tài)性問題。實現(xiàn)時,前者由在繼承方式前加virtual; 后者靠純虛函數(shù)實現(xiàn)。虛函數(shù)與純虛函數(shù)對比:純在抽象類中,被“初始化”為0的函數(shù)。沒有實際意義,為派生類保留名字,方便該函數(shù)實現(xiàn)多態(tài)性。虛函數(shù)有實際意義,也是為實現(xiàn)多態(tài)性服務。第54頁/共55頁感謝您的觀看!第55頁/共55頁
- 溫馨提示:
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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 5段太尉逸事狀
- 讀后感作文輔導1
- 有機磷農(nóng)藥中毒終極
- 電解池的應用(教育精品)
- 庫存管理流程及改善課件
- 廬陽區(qū)XX小學四年級數(shù)學上冊-1-大數(shù)的認識-第4課時-億以內(nèi)數(shù)的大小比較課件-新人教版
- 合同策劃與合同分析
- 五年級下冊語文課件-1春光染綠我們雙腳-蘇教版
- 闌尾炎的教學查房csp課件
- 基準和輪廓度公差課件
- 建立開放式公共物流平臺體系-推動制造業(yè)及物流的聯(lián)動課件
- 三(323)家長會
- 策略管理Chapter3內(nèi)部分析獨特能力競爭優(yōu)勢與獲利能力課件
- 江城子(教育精品)
- 水果寶寶去旅行 (2)(教育精品)