C++語言程序設計教程(第二版)清華出版 楊進才第8章 繼承與派生_第1頁
C++語言程序設計教程(第二版)清華出版 楊進才第8章 繼承與派生_第2頁
C++語言程序設計教程(第二版)清華出版 楊進才第8章 繼承與派生_第3頁
C++語言程序設計教程(第二版)清華出版 楊進才第8章 繼承與派生_第4頁
C++語言程序設計教程(第二版)清華出版 楊進才第8章 繼承與派生_第5頁
已閱讀5頁,還剩40頁未讀 繼續免費閱讀

下載本文檔

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

文檔簡介

1、第第8 8章章 繼承與派生繼承與派生制作人:沈顯君 楊進才C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生第第8 8章章 繼承與派生繼承與派生學習目標1. 掌握派生與繼承的概念與使用方法;2. 能夠運用繼承機制對現有的類進行重用;3. 掌握繼承中的構造函數與析構函數的調用順序;4. 為派生類設計合適的構造函數初始化派生類;5. 掌握處理多繼承時的二義性問題; 6. 掌握虛基類的概念與使用方法。 8.1 繼承與派生 在C+中,可以利用已有的類來定義新的類,新類將擁有原有類的全部特性,原有類被稱為基類基類(Ba

2、se class)或父類(Super class),新產生的類被稱為派生類派生類(Derived class)或子類(Sub class)。派生類擁有基類的特性稱作繼承繼承,由基類產生派生類的過程稱為派生派生。 8.1.1 繼承的概念繼承的概念 每一個派生類都有且僅有一個基類,派生類可以看作是基類的特例,它增加了某些基類所沒有的性質。這種繼承方式,稱為單繼承單繼承或單向繼承。 現實生活中,子女的外貌、血型往往不是僅僅繼承自父親或母親,而是將父母親的特點都繼承下來。與之相類似,如果一個派生類有兩個或兩個以上的基類,則稱為多繼承多繼承或多重繼承。 派生類又作為基類,繼續派生新的類, 這樣的派生方式

3、稱為多層派生多層派生,從繼承的角度看稱為多層繼承多層繼承。C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.1.1 繼承的概念繼承的概念派生類定義的語法為: class 派生類名:繼承方式派生類名:繼承方式1 基類名基類名1, 繼承方式繼承方式2 基類名基類名2, private: 派生類的私有數據和函數派生類的私有數據和函數 public: 派生類的公有數據和函數派生類的公有數據和函數 protected: 派生類的保護數據和函數派生類的保護數據和函數;8.1.2 派生類實現派生類實現1. 派生類的定義

4、派生類的定義C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生“繼承方式1 基類名1, 繼承方式2 基類名2,”為基類名表基類名表, 表示當前定義的派生 類的各個基類。如果基類名表中只有一個基類,表示定義的是單繼承;如果基類名表中有多個 基類,表示定義的是多繼承多繼承。繼承方式指定了派生類成員以及類外對象對于從基類繼承來的成員的訪問權限 。繼承方式有三種:public: 公有繼承; private: 私有繼承; protected:保護繼承。8.1.2 派生類實現派生類實現class Clock private: int H,M,S; public: void SetTime

5、(int H=0,int M=0,int S=0); void ShowTime(); Clock(int H=0,int M=0,int S=0); Clock();class AlarmClock: public Clockprivate: int AH,AM; /響鈴的時間響鈴的時間 bool OpenAlarm; /是否關閉鬧鐘是否關閉鬧鐘public: void SetAlarm(int AH, int AM); /設置響鈴時設置響鈴時間間 void SwitchAlarm(bool Open=true); /打開打開/關閉鬧關閉鬧鈴鈴 void ShowTime(); /顯示當前時

6、間與鬧鈴時顯示當前時間與鬧鈴時間間C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生在派生類的定義中,每一種繼承方式只限定緊跟其后的那個基類。如果不顯式給出繼承方式,系統默認為私有繼承默認為私有繼承。 【例如】在普通的時鐘類Clock基礎上派生出鬧鐘類AlarmClock:類類 名名成成 員員 名名AlarmClock :Clock:H, M, SSetTime()ShowTime()AH, AM, OpenAlarmSetAlarm()SwitchAlarm()ShowTime()AlarmClock()派生類派生類AlarmClock的成員構成圖的成員構成圖(表表) 8.

7、1.2 派生類實現派生類實現C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生2.派生類的實現方式派生類的實現方式 (1) 吸收基類成員吸收基類成員 基類的全部成員被派生類繼承,作為派生類成員的一部分。如:Clock類中的數據成員H、M、S, 成員函數SetTime()、ShowTime()經過派生,成為派生類AlarmClock的成員。 (2) 改造基類成員改造基類成員 派生類根據實際情況對繼承自基類的某些成員進行限制和改造。對基類成員的訪問限制主要通過繼承方式來實現;對基類成員的改造主要通過同名覆蓋同名覆蓋來實現,即在派生類中定義一個與基類成員同名的新成員(如果是成員函數

8、,則函數參數表也必須相同,否則,C+會認為是函數重載)。當通過派生類對象調用該成員時,C+將自動調用派生類中重新定義的同名成員,而不會調用從基類中繼承來的同名成員,這樣派生類中的新成員就“覆蓋”了基類的同名成員。由此可見,派生類中的成員函數具有比基類中同名成員函數更小的作用域。如:AlarmClock類中的成員函數ShowTime()覆蓋了基類Clock中的同名成員函數ShowTime()。 (3) 添加新成員添加新成員 派生類在繼承基類成員的基礎之上,根據派生類的實際需要,增加一些新的數據成員和函數成員,以描述某些新的屬性和行為。如:AlarmClock添加了數據成員AH、AM、OpenAl

9、arm, 成員函數SetAlarm()、SwitchAlarm()。8.1.2 派生類實現派生類實現C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生3. 繼承的性質繼承的性質 (1) 繼承關系是可以傳遞的繼承關系是可以傳遞的 在派生過程中,一個基類可以同時派生出多個派生類,派生出來的新類也同樣可以作為基類再繼續派生新的派生類。這樣,就形成了一個相互關聯的類的家族,有時也稱作類族類族。在類族中,直接派生出某類的基類稱為直接基類直接基類,基類的基類甚至更高層的基類稱為間接基類間接基類,比如類A派生出類B,類B又派生出類C,則類B是類C的直接基類,類A是類B的直接基類,而類A稱為

10、類C的間接基類。 (2)繼承關系不允許循環)繼承關系不允許循環 在派生過程中,不允許類A派生出類B,類B又派生出類C,而類C又派生出類A。8.1.3 繼承與組合繼承與組合C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 繼承繼承描述的是一般類與特殊類的關系,類與類之間體現的是“is a kind of”,即如果在邏輯上A是B的一種(is a kind of),則允許A繼承B的功能和屬性。例如汽車(automobile)是交通工具(vehicle)的一種,小汽車(car)是汽車的一種。那么類automobile可以從類vehicle派生,類car可以從類automobile派

11、生。 組合組合描述的是整體與部分的關系,類與類之間體現的是“is a part of”,即如果在邏輯上A是B的一部分(is a part of),則允許A和其他數據成員組合為B。例如:發動機、車輪、電池、車門、方向盤、底盤都是小汽車的一部分,它們組合成汽車。而不能說發動機是汽車的一種。 繼承和組合既有區別,也有聯系,某些比較復雜的類,既需要使用繼承,也需要使用組合,二者一起使用。 在某些情況下,繼承與組合的實現還可以互換。在多繼承時,一個派生類有多個直接基類,派生類實際上是所有基類屬性和行為的組合。派生類是對基類的擴充,派生類成員一部分是從基類中來,因此派生類組合了基類。既然這樣,派生類也可以

12、通過組合類實現。例如:AlarmClock類可以通過組合Clock類實現,從功能上講,基本的時鐘功能是鬧鐘功能的一部分。 什么時候使用繼承,什么時候使用組合,要根據問題類與類之間的具體關系,順其自然,權衡考慮順其自然,權衡考慮。 8.2 繼承的方式C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 基類的公有成員在派生類中仍然為公有成員,可以由派生類對象和派生類成員函數直接訪問。 基類的私有成員在派生類中,無論是派生類的成員還是派生類的對象都無法直接訪問。 保護成員在派生類中仍是保護成員,可以通過派生類的成員函數訪問,但不能由派生類的對象直接訪問。8.2.1 公有繼承公有繼承

13、公有方式繼承的特點:公有方式繼承的特點: F注意注意: : 對基類成員的訪問,一定要分清是通過派生類對象訪問還是通過派生類成員函數訪問。 C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 【例【例8-1】公有繼承及其訪問 將點理解為半徑長度為0的圓,Point(點)類公有派生出新的Circle(圓)類。圓類具備Point類的全部特征,同時自身也有自己的特點:圓有半徑。 8.2.1 公有繼承公有繼承123456789101112131415161718192021/Point.h#includeusing namespace std;class Pointprivate:in

14、t X,Y;public:Point(int X=0,int Y=0) this-X=X,this-Y=Y; void move(int OffX, int OffY) X+=OffX, Y+=OffY; void ShowXY() cout(X,Y)endl;C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.1 公有繼承公有繼承1234567891011121314151617181920212223242526/* Circle.h * 從Point類派生出圓類(Circle) */#includepoint.hconst double PI=3.14159;cl

15、ass Circle :public Pointprivate:double radius; /半徑public: Circle(double R, int X, int Y):Point(X,Y) radius=R; double area() /求面積 return PI*radius*radius; void ShowCircle() coutCentre of circle:; ShowXY(); coutradius:radiusendl; ;類類 名名成成 員員 名名訪問權限訪問權限CirclePoint:X, Yprivate不可訪問不可訪問move()publicpublicS

16、howXY()publicpublicradiusprivatearea()publicShowCircle()publicCircle()publicC+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.1 公有繼承公有繼承313233343536373839404142434445/* p8_1.cpp * Circle 類的使用 */#include Circle.husing namespace std;int main() Circle Cir1(10,100,200);Cir1.ShowCircle(); coutarea is:Cir1.area()endl

17、;Cir1.move(10,20); Cir1.ShowXY(); return 0;運行結果運行結果Centre of circle:(100,200) radius:10area is:31415.9(110,220) C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.1 公有繼承公有繼承1234567891011121314151617181920212223242526/* Circle.h * 從Point類派生出圓類(Circle) */#includepoint.hconst double PI=3.14159;class Circle :public

18、Pointprivate:double radius; /半徑public: Circle(int X, int Y, double R):Point(X,Y) radius=R; double area() /求面積 return PI*radius*radius; void ShowCircle() coutCentre of circle:; ShowXY(); coutradius:radiusendl; ;程序解釋程序解釋 派生類Circle繼承了Point類的除構造函數外的全部成員,擁有從基類繼承過來的成員與派生類新添加的成員的總和。繼承方式為公有繼承,這時,基類中的公有成員在派生

19、類中訪問屬性保持原樣,派生類的成員函數及對象可以訪問基類派生的的公有成員?;愒械耐獠拷涌?公有成員函數), 如ShowXY()和move()變成了派生類外部接口的一部分。在Circle的構造函數中,為了給從基類繼承來的數據成員賦初值,使用了初始化列表,其格式與組合類相同8.2.2 私有繼承私有繼承C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 基類的公有成員和保護成員被繼承后作為派生類的私有成員,即基類的公有成員和保護成員被派生類吸收后,派生類的其他成員函數可以直接訪問它們,但是在類外部,不能通過派生類的對象訪問它們。 基類的私有成員在派生類中不能被直接訪問。無論是派

20、生類的成員還是通過派生類的對象,都無法訪問從基類繼承來的私有成員。 經過私有繼承之后,所有基類的成員都成為了派生類的私有成員或不可訪問的成員,如果進一步派生的,基類的全部成員將無法在新的派生類中被訪問。因此,私有繼承之后,基類的成員再也無法在以后的派生類中發揮作用,實際是相當于中止了基類的繼續派生,出于這種原因,一般情況下私有繼承的。 私有方式繼承的特點:私有方式繼承的特點: C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 【例【例8-2】私有繼承派生類的實現及其訪問8.2.2 私有繼承私有繼承/ Circle2.h#includepoint.hconst double

21、PI=3.14159;class Circle :private Point private: double radius; /半徑 public:Circle(double R, int X, int Y):Point(X,Y) radius=R; double area() /求面積 return PI*radius*radius; void ShowCircle() coutCentre of circle:; ShowXY(); coutradius:radiusendl;void move(int OffX, int OffY) Point:move(OffX,OffY);類類 名名

22、成成 員員 名名訪問權限訪問權限CirclePoint:X,Yprivate不可訪問move()publicprivateShowXY()publicprivateradiusprivatearea()publicShowCircle()publicCircle()publicCircle2.h的完整程序如課件所示。C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.2 私有繼承私有繼承運行結果運行結果Centre of circle:(100,200) radius:10area is:31415.9#include Circle2.husing namespace

23、std;int main() Circle Cir1(10,100,200);Cir1.ShowCircle();coutarea is:Cir1.area()endl;Cir1.move(10,20); /同名覆蓋 / Cir1.ShowXY(); /錯誤,ShowXY()繼承為私有成員函數 return 0;程序解釋程序解釋對比兩個示例程序,可以看出:由于是私有繼承私有繼承,基類中的所有成員在派生類中都成為私有成員,因此派生類對象不能直接訪問任何一個基類的成員。類Circle的對象Cir1調用的都是派生類自身的公有成員。本例僅僅對派生類的實現作了適當的修改,基類和主程序部分沒有做任何改動,

24、程序運行的結果同前例。由此可見面向對象程序設計封裝性的優越性優越性,這正是面向對象程序設計可重用與可擴充性的一個實際體現。8.2.3 保護繼承保護繼承C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 基類的公有成員和保護成員被繼承后作為派生類的保護成員。 基類的私有成員在派生類中不能被直接訪問。 修改Circle2.h,將派生類的繼承方式改為保護繼承,其它部分不變:保護繼承的特點:保護繼承的特點: /circle3.h#include “piont.h”class Circle :protected point/類成員定義類類 名名成成 員員 名名訪問權限訪問權限Circl

25、ePoint:X,Yprivate不可訪問move()publicprotectedShowXY()publicprotectedradiusprivatearea()publicShowCircle()publicCircle()publicC+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.3 保護繼承保護繼承運行結果運行結果Centre of circle:(100,200) radius:10area is:31415.9(110,30) #include Circle3.husing namespace std;int main() Circle Cir1(1

26、0,100,200);Cir1.ShowCircle();coutarea is:Cir1.area()endl;Cir1.move(10,20); /同名覆蓋 / Cir1.ShowXY(); /錯誤,ShowXY()繼承為保護成員函數 return 0; 程序解釋程序解釋:private、protected兩種繼承方式下,基類所有成員在派生類中的訪問屬性都是完全相同的。即在派生類中可以訪問基類的公有、保護成員不可訪問基類的私有成員。 如果將派生類作為新的基類繼續派生時, private、protected兩種繼承方式區別區別就出現了。假設類B以私有方式繼承自類A,則無論B類以什么方式派生出

27、類C,類C的成員和對象都不能訪問間接從A類中繼承來的成員。但如果類B是以保護方式繼承自類A,那么類A中的公有和保護成員在類B中都是保護成員。類B再派生出類C后,如果是公有派生或保護派生,則類A中的公有和保護成員被類C間接繼承后,類C的成員函數可以訪問間接從類A中繼承來的成員。即類A的成員可以沿繼承樹繼續向下傳播沿繼承樹繼續向下傳播。C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 【例【例8-2 】保護繼承與保護成員的訪問 修改例8-1,除將基類Point的數據成員X和Y的訪問屬性改為protected外,又增加了一個派生類:Cylinder(圓柱體)類。Cylinder類

28、保護繼承自類circle。程序實現如下: 8.2.3 保護繼承保護繼承123456789101112131415161718192021/Point2.h#includeusing namespace std;class Pointprotected:int X,Y;public:Point(int X=0,int Y=0) this-X=X,this-Y=Y; void move(int OffX, int OffY) X+=OffX, Y+=OffY; void ShowXY() cout(X,Y)endl;C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.3 保

29、護繼承保護繼承1234567891011121314151617181920212223242526272829303132/* p8_2.cpp * 從circle類派生出圓柱類(Cylinder) */#includepoint2.hconst double PI=3.14159;class Circle :protected Pointprotected:double radius; /半徑public: Circle(double R, int X, int Y):Point(X,Y) radius=R; double area() /求面積 return PI*radius*radi

30、us; void ShowCircle() coutCentre of circle:; ShowXY(); coutradius:radiusendl;class Cylinder: protected Circleprivate:double height;public: Cylinder(int X, int Y, double R, double H):Circle(R,X,Y)333435363738394041424344454647484950515253545556 height=H; double area() return 2*Circle:area()+2*PI*radi

31、us*height; double volume() return Circle:area()*height;void ShowCylinder() ShowCircle(); coutheight of cylinder:heightendl;void main() Cylinder CY(100,200,10,50);CY.ShowCylinder();couttotal area:CY.area()endl;coutvolume:CY.volume();運行結果運行結果Centre of circle:(100,200) radius:10height of cylinder:50tot

32、al area :3769.11volume : 15707.9 C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.3 保護繼承保護繼承1234567891011121314151617181920212223242526272829303132/* p8_2.cpp * 從circle類派生出圓柱類(Cylinder) */#includepoint2.hconst double PI=3.14159;class Circle :protected Pointprotected:double radius; /半徑public: Circle(double R, i

33、nt X, int Y):Point(X,Y)radius=R; double area() /求面積return PI*radius*radius; void ShowCircle() coutCentre of circle:; ShowXY(); coutradius:radiusendl;class Cylinder: protected Circleprivate:double height;public: Cylinder(int X, int Y, double R, double H):Circle(R,X,Y)333435363738394041424344454647484

34、950515253545556 height=H; double area() return 2*Circle:area()+2*PI*radius*height; double volume() return Circle:area()*height;void ShowCylinder() ShowCircle(); coutheight of cylinder:heightendl;void main() Cylinder CY(100,200,10,50);CY.ShowCylinder();couttotal area:CY.area()endl;coutvolume:CY.volum

35、e(); Circle保護繼承自類Point,因此類Circle為子類,類Point為父類,對于該子類來講,保護成員與公有成員具有相同的訪問特性。所以派生類的成員函數ShowCircle()可以訪問基類從基類繼承而來的保護成員,當然它也可以調用從基類繼承來的公有成員函數ShowXY()。 類Circle沿類的繼承樹繼續派生出類Cylinder,繼承方式依然為保護繼承,因此,在類cylinder中,它間接從類Point中繼承了四個保護成員:數據成員X、Y,以及成員函數move()、ShowXY();同時它也直接從其父類Circle中繼承了3個類成員:數據成員radius, 成員函數ShowCir

36、cle()、area(),它們都以保護成員的身份出現在類Cylinder中。因此,在類Cylinder的成員函數ShowCylinder()中,不僅可以訪問從父類Circle中直接繼承來的成員函數ShowCircle(),而且可以訪問沿繼承樹從基類Point中間接繼承來的數據成員X和Y。 當通過類Cylinder的對象CY調用成員函數area()時,由于對象CY擁有兩個同名成員函數area(),一個是從其父類Circle繼承來的,一個是類Cylinder自己新增的,二者函數體實現完全不同。類Circle的成員函數area()和派生類Cylinder新增的成員函數area()都具有類作用域,二者

37、的作用范圍不同,是相互包含的兩個層,派生類在內層。由于,派生類Cylinder聲明了一個和其父類circle成員同名的新成員area(),派生的新成員函數就覆蓋了外層父類的同名成員函數,直接使用成員名只能訪問到派生類自己新增的同名成員函數。C+利用同名覆蓋原則,自動選擇調用類Cylinder新增的成員函數area(),輸出圓柱體的總的表面積,這再一次體現了繼承機制所產生的程序重用性和可擴充性。C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.2.3 保護繼承保護繼承三種繼承方式下,基類成員在派生類中的訪問控制屬性總結如圖:三種繼承方式下,基類成員在派生類中的訪問控制屬性總

38、結如圖: 基類屬性基類屬性繼承方式繼承方式 publicprotectedprivatepublicpublicprotected不可訪問protectedprotectedprotected不可訪問privateprivateprivate不可訪問8.3 派生類的構造與析構 1.派生類構造函數的定義派生類構造函數的定義C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 派生類名派生類名(參數總表參數總表): 基類名基類名1(參數表參數表1),.,基類名基類名m (參數表參數表m),成員對象名成員對象名1(成員對象參數表成員對象參數表1),.,成員對象名成員對象名n(成員對象

39、參數表成員對象參數表n) 派生類新增成員的初始化;派生類新增成員的初始化; 基類名1(參數表1),.,基類名m (參數表m)稱為基類成員的初始化表基類成員的初始化表。 成員對象名1(成員對象參數表1),.,成員對象名n(成員對象參數表n) 為成員對象成員對象 的初始化表的初始化表。基類成員的初始化表與成員對象的初始化表構成派生類構造函數的初始化表初始化表。在派生類構造函數的參數總表參數總表中,需要給出基類數據成員的初值、成員對象數 據成員的初值、新增一般數據成員的初值。在參數總表之后,列出需要使用參數進行初始化的基類名、成員對象名及各自 的參數表,各項之間使用逗號分隔。基類名、對象名之間的次序

40、無關緊要,它們各自出現的順序可以是任意的任意的。在 生成派生類對象時,程序首先會使用這里列出的參數,調用基類和成員對象的 構造函數。8.3 派生類的構造與析構 什么時候需要定義派生類的構造函數?什么時候需要定義派生類的構造函數? C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 如果基類定義了帶有形參表的構造函數時,派生類就應當定義構造函數,提供一個將參數傳遞給基類構造函數的途徑,保證在基類進行初始化時能夠獲得必要的數據。 調用基類構造函數; 調用內嵌成員對象的構造函數,調用順序按照它們在類中定義的順序 。 派生類自己的構造函數。 如果基類沒有定義構造函數,派生類也可以不定

41、義構造函數,全部采用默認的構造函數,這時新增成員的初始化工作可以用其他公有成員函數來完成。2 單繼承的構造與析構單繼承的構造與析構單繼承時,派生類構造函數調用的一般次序如下: 當派生類對象析構時,各析構函數的調用順序正好相反正好相反。首先調用派生類析構 函數(清理派生類新增成員);然后調用派生類成員對象析構函數(清理派生類新 增的成員對象);最后調用基類析構函數(清理從基類繼承來的基類子對象)。 8.3 派生類的構造與析構 C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生 【例【例8-3】單繼承的構造與析構。 為了說明單繼承的構造,由Point類派生出Circle類,再由兩

42、個同心Circle類對象與高度height構成空管Tube類。構成空管的兩個同心圓的外圓從Circle類繼承,內圓組合Circle類對象InCircle。Tube類的層次結構圖如圖: 8.3 派生類的構造與析構 123456789101112131415161718192021222324252627282930313233343536/* p8_3.cpp * 多層繼承的構造函數與析構函數 */#includeusing namespace std;class Pointprivate:int X,Y;public:Point(int X=0,int Y=0) this-X=X,this-Y

43、=Y coutpoint(X,Y) constructing.endl;Point()coutpoint(X,Y) destructing.endl;class Circle :protected Pointprotected:double radius; /半徑public:Circle(double R=0,int X=0, int Y=0):Point(X,Y) radius=R; coutcircle constructing, radius:Rendl;Circle() coutcircle destructing, radius:radiusendl;C+語語言言程程序序設設計計教

44、教程程 第第8章章繼繼承承與與派派生生37383940414243444546474849505152535455565758class tube: protected Circleprivate: double height; Circle InCircle;public: tube(double H,double R1, double R2=0, int X=0, int Y=0 ):InCircle(R2,X,Y),Circle(R1,X,Y) height=H; couttube constructing, height:Hendl; tube() couttube destructi

45、ng, height:heightendl;int main() tube TU(100,20,5); return 0;運行結果運行結果point(0,0) constructing.circle constructing, radius:20point(0,0) constructing.circle constructing, radius:5tube constructing, height:100tube destructing, height:100circle destructing, radius:5point(0,0) destructing.circle destructi

46、ng, radius:20point(0,0) destructing. 定義了一個派生類Tube的對象TU,首先試圖調用類Tube的構造函數; 類Tube是派生類,由基類Circle派生,于是試圖調用Circle類的構造函數; 類Circle的基類是Point, 沿繼承樹上溯至頂層基類Point,調用Point類的構造函數; Tube同時又是一個組合類,由對象InCircle組合而成,于是,再從頂層基類Point開始,依次調用調用Point類的構造函數、Circle的構造函數。 當退出主函數之前,程序沿繼承樹自底向上依次調用各類的析構函數,其順序與構造函數順序正好相反。 在C+中,類型兼容主

47、要指以下三種情況: 派生類對象可以賦值給基類對象。 派生類對象可以初始化基類的引用。 派生類對象的地址可以賦給指向基類的指針。C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.4 類型兼容 類型兼容類型兼容是指在公有派生的情況下,一個派生類對象可以作為基類的對象來使用的情況。類型兼容又稱為類型賦值兼容或類型適應。 【例【例8-4】演示類的兼容性。 前面我們定義了類Point,它公有派生出類Circle,后者進一步公有派生出類Cylinder。我們可以通過這個單繼承的例子來驗證類型兼容規則。C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生運行結果運行結果

48、(1,1)(20,20)(300,300)(300,300)(20,20) 8.4 類型兼容123456789101112131415161718192021222324252627282930313233343536373839/* p8_4.cpp * 從circle類公有派生出圓柱類Cylinder * 演示類的兼容性 */#includeCircle.hclass Cylinder: public Circleprivate:double height;public: Cylinder(double R, int X, int Y, double H):Circle(R,X,Y) he

49、ight=H; void ShowCylinder() ShowCircle(); coutheight of cylinder:heightShowXY(); Pp=&Cir; /將派生類對象地址賦給指向基類的指針 Pp-ShowXY(); Pp=&CY; /將派生類對象地址賦給指向基類的指針 Pp-ShowXY(); Circle & RC=CY; /Circle類引用引用了派生類Cylinder對象 RC.ShowXY(); P=Cir; /Circle類對象賦值給基類Point類對象 P.ShowXY(); return 0;定義了Point類型的指針Pp 指向

50、了Point類對象 指向了Circle類對象 指向了Cylinder類對象 Pp調用了Point 類的成員函數ShowXY(), 顯示了Point類對象的中心坐標值。 調用了Point 類的成員函數ShowXY(), 顯示了Circle類對象的中心坐標值。 調用了Point 類的成員函數ShowXY(), 顯示了Cylinder類對象的中心坐標值。 P8_4.cpp的正確程序和運行結果如課件所示,注意構造函數中半徑R定義的位置順序。還可以將display()形參改為基類指針基類指針:C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.4 類型兼容void display(P

51、oint p) p.ShowXY();int main() Point P(1,1); /Point類對象 Circle Cir(15,20,20); /Circle類對象 Cylinder CY(15,300,300, 50); /Cylinder類對象 display(P); /顯示對象P的中心坐標 display(Cir); /顯示對象Cir的中心坐標 display(CY); /顯示對象CY的中心坐標 return 0;void display(Point& p) p.ShowXY();如將上述程序改為:可將display()的參數改為引用形式:void display(Poi

52、nt* p) p-ShowXY(); 這樣,可以分別把基類對象P、派生類Circle的對象Cir和派生類Cylinder的對象CY的地址作為實參傳給基類類型指針,由C+編譯器實現隱式的類型轉換隱式的類型轉換。根據C+類型兼容規則, p可以引用任何point的公有派生類對象。 C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.5 多繼承 多繼承多繼承(multiple inheritance,MI)是指派生類具有兩個或兩個以上的直接基類(direct class)。 多繼承時派生類構造函數執行的一般次序如下: 調用各基類構造函數;各基類構造函數調用順序按照基類被繼承時聲明的

53、順序,從左向右依次進行。 調用內嵌成員對象的構造函數;成員對象的構造函數調用順序按照它們在類中定義的順序依次進行。 調用派生類的構造函數;8.5.1 多繼承的構造與析構多繼承的構造與析構F注意注意: : 在繼承層次圖中,處于同一層次的各基類構造函數的調用順序取決于定義該派生類時所指定的各基類的先后順序,與派生類構造函數定義時初始化表中所列的各基類構造函數的先后順序無關。 對同一個基類,不允許直接繼承兩次。 C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.5.2 二義性問題二義性問題 一般來說,在派生類中對于基類成員的訪問應該是唯一的,但是,由于多繼承中派生類擁有多個基類

54、,如果多個基類中擁有同名的成員,那么,派生類在繼承各個基類的成員之后,當我們調用該派生類成員時,由于該成員標識符不唯一,出現二義性二義性,編譯器無法確定到底應該選擇派生類中的哪一個成員,這種由于多繼承而引起的對類的某個成員訪問出現不唯一的情況就稱為二義性問題?!纠纠?-5】多繼承的二義性。 例如:我們可以定義一個小客車類car和一個小貨車類Wagon,它們共同派生出一個客貨兩用車類StationWagon。StationWagon繼承了小客車的特征,有座位seat,可以載客;又繼承了小貨車的特征,有裝載車廂load, 可以載貨。程序實現如下:7891011121314151617181920

55、21class Car /小客車類private: int power; /動力 int seat; /座位public:Car(int power,int seat)this-power=power,this-seat=seat;void show() coutcar power:power seat:seatpower=power,this-load=load;void show() coutwagon power:power load:loadendl;class StationWagon :public Car, public Wagon /客貨兩用車類public:StationWa

56、gon(int power, int seat,int load) :Wagon(power,load), Car(power,seat)void ShowSW() coutStationWagon:endl; Car:show(); Wagon:show(); ;int main() StationWagon SW(105,3,8); /SW.show(); /錯誤,出現二義性 SW.ShowSW(); return 0;運行結果運行結果StationWagon:car power:105 seat:3wagon power:105 load:8 小客車類Car和小貨車類Wagon共同派生出

57、客貨兩用車類StationWagon,后者繼承了前者的屬性power和行為show()。 當通過StationWagon類的對象SW訪問show ()時,程序出現編譯錯誤。這是因為基類Car和Wagon各有一個成員函數show (),在其共同的派生類StationWagon中就有兩個相同的成員函數,而程序在調用時無法決定到底應該選擇哪一個成員函數。 C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.5.2 二義性問題二義性問題(1) 成員名限定成員名限定 通過類的作用域分辨符明確限定出現歧義的成員是繼承自哪一個基類。 例如:程序第47、48兩行使用了Car:show()與

58、Wagon:show()來表明調用哪個類的show().(2) 成員重定義成員重定義 在派生類中新增一個與基類中成員相同的成員,由于同名覆蓋,程序將自動選擇派生類新增的成員。 可以對派生類StationWagon的ShowSW()改名為show()。這樣, 類StationWagon中的show()覆蓋了基類中的兩個同名的show(),使用SW.show();時不會出現二義性問題。通常有兩種方法可以解決通常有兩種方法可以解決:C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.6 虛基類 在多繼承中,在派生類的對象中,同名數據成員在內存中同時擁有多個拷貝,同一個成員函數會有

59、多個映射,出現二義性,這種二義性為間接二義性間接二義性。 【例【例8-6】多重繼承的間接二義性。 假定類Car、Wagon從共同的基類Automobile(汽車)派生出來,程序如下:1234567891011121314151617181920/* p8_6.cpp * 多繼承的二義性 */#includeusing namespace std;class Automobile /汽車類private: int power; /動力public: Automobile(int power) this-power=power; void show() cout power:seat=seat;

60、void show() coutcar:; Automobile:show(); cout seat:seatload=load; void show() coutwagon:; Automobile:show(); cout load:loadendl; ;C+語語言言程程序序設設計計教教程程 第第8章章繼繼承承與與派派生生8.6 虛基類5354555657585960616263646566676869707172class StationWagon :public Car, public Wagon /客貨兩用車類public: StationWagon(int CPower, int WPower,int seat

溫馨提示

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

評論

0/150

提交評論