最新C++實用教程[鄭阿奇主編]12_第1頁
最新C++實用教程[鄭阿奇主編]12_第2頁
最新C++實用教程[鄭阿奇主編]12_第3頁
最新C++實用教程[鄭阿奇主編]12_第4頁
最新C++實用教程[鄭阿奇主編]12_第5頁
已閱讀5頁,還剩50頁未讀 繼續免費閱讀

下載本文檔

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

文檔簡介

1、第12章 繼承和派生 12.1 繼承和派生概述n12.1.1 繼承的概念n1. 繼承和概括n繼承(Inheritance),是指一個事物可以繼承其父輩全部或部分特性,同時本身還有自己的特性。 n2. 類繼承相關概念n在C+中,當一個新類從一個已定義的類中派生后,新類不僅繼承了原有類的屬性和方法,并且還擁有自己新的屬性和方法,稱為類的繼承和派生。被繼承的類稱為基類(Base class)或超類(Super class)(又稱父類),在基類或父類上建立的新類稱為派生類(Derived class)或子類(Sub class)。3. 類層次關系的描述方法上述父類和子類的關系稱為類層次或繼承關系。在類

2、設計時,常常將這些關系用樹來描述。例如,下圖就是用樹來描述學校人員類的層次關系。12.1.2 繼承的特性n在C+中,類的繼承具有下列特性:n(1)單向性。 n(2)傳遞性。 n(3)可重用性。n12.1.3 派生類的定義n在C+中,一個派生類的定義可按下列格式:nclass:,nnn; 12.2 繼承方式 nC+繼承方式有三種:public(公有)、private(私有)及protected(保護)n12.2.1 公有繼承n公有繼承(public)方式具有下列特點: n(1)在派生類中,基類的公有成員、保護成員和私有成員的訪問屬性保持不變。n(2)派生類對象只能訪問派生類和基類的公有(publ

3、ic)成員。 例Ex_PublicDerived 派生類的公有繼承示例。 n#include n#include nusing namespace std;nclass CPersonnnpublic:nCPerson(char *name, int age, char sex = M)nnstrncpy(this-name, name, 20);nthis-age = age; this-sex = sex;nnvoid SetNameAndSex( char *name, char sex = M) / 更改姓名和性別nnstrncpy(this-name, name, 20);this-

4、sex = sex;nnprotected:nvoid SetAge(int age)nnthis-age = age;nnvoid ShowInfo()/ 顯示信息nncout姓名:nameendl;ncout性別:(sex=M?男:女)endl;ncout年齡:agestuno, no, 20);nnvoid SetScore( float s1, float s2, float s3 )nnscore0 = s1;score1 = s2;score2 = s3;ntotal = s1 + s2 + s3;ave = total / (float)3.0;nnvoid SetNoAndAg

5、e(char *no, int age)nstrncpy(this-stuno, no, 20);this-SetAge( age ); nvoid ShowAll()nnShowInfo();/ 調用基類的成員函數ncout學號:stunoendl;ncout三門成績:score0tscore1tscore2endl;ncout總成績和平均分:totaltaveendl;nnprivate:ncharstuno20;/ 學號nfloatscore3,ave, total;/ 三門成績、平均分和總分n;nint main()nnCStudent one(LiMing, 21050101, 19

6、 ); / Anone.SetScore( 90, 80, 84);/ Bnone.ShowAll();/ 調用派生類的公有成員函數none.SetNameAndSex(WangFang, W);n / 調用基類的公有成員函數none.SetNoAndAge(21050102, 18 );n / 調用派生類的公有成員函數none.ShowAll();/ 調用派生類的公有成員函數nreturn 0;n程序運行結果如下:12.2.2 私有繼承n私有繼承(private)方式具有下列特點:n(1)在派生類中,基類的公有成員、保護成員和私有成員的訪問屬性都將變成私有(private),且基類的私有成員

7、在派生類中被隱藏。 n(2)由于基類的所有成員在派生類中都變成私有的,因此基類的所有成員在派生類的子類中都是不可見的。 n(3)派生類對象只能訪問派生類的公有成員,不能訪問基類的任何成員。例Ex_PrivateDerived 派生類的私有繼承示例。 n#include n#include nusing namespace std;nclass CPersonnnpublic:nCPerson(char *name, int age, char sex = M)nnstrncpy(this-name, name, 20);nthis-age = age; this-sex = sex;nnvoi

8、d SetNameAndSex( char *name, char sex = M)n / 更改姓名和性別nnstrncpy(this-name, name, 20);this-sex = sex;nnprotected:nvoidSetAge(intage)nnthis-age=age;nnvoidShowInfo()/顯示信息顯示信息nncout姓名:姓名:nameendl;ncout性別:性別:(sex=M?男男:女女)endl;ncout年齡:年齡:agestuno, no, 20);nnpublic:nvoid SetScore( float s1, float s2, float

9、s3 )nnscore0 = s1;score1 = s2;score2 = s3;ntotal = s1 + s2 + s3;ave = total / (float)3.0;nnvoid SetNoAndAge(char *no, int age)nnstrncpy(this-stuno, no, 20);this-SetAge( age );nnvoid ShowAll()nnShowInfo();/ 調用基類的保護成員函數ncout學號:stunoendl;ncout三門成績:score0tscore1tscore2endl;ncout總成績和平均分:totaltaveendl;n/

10、修改的代碼nvoid SetNameAndSex( char *name, char sex = M) / 更改姓名和性別nnCPerson:SetNameAndSex(name, sex); / 調用基類的公有成員函數nnprivate:ncharstuno20;/ 學號nfloatscore3,ave, total;n / 三門成績、平均分和總分n;nint main()nnCStudent one(LiMing, 21050101, 19 );none.SetScore( 90, 80, 84);none.ShowAll();none.SetNameAndSex(WangFang, W)

11、;none.SetNoAndAge(21050102, 18 );none.ShowAll();nreturn 0;nn程序運行結果同前。12.2.3 保護繼承n保護繼承(protected)方式具有下列特點:n(1)在派生類中,基類的公有成員、保護成員的訪問屬性都將變成保護的。 n(2)同私有繼承一樣,在保護繼承方式下,派生類中仍可訪問基類的公有成員和保護成員。 n12.3 派生類的構造和析構 n12.3.1 構造和析構次 1. 單繼承n如圖12.2(a)所示,A類是B類的基類,B類又是C類的基類,它們是多層單繼承方式n其代碼如下: nclass Annpublic:nA()cout執行A的

12、構造函數endl;nA()cout執行A的析構函數endl;n;nclass B: public Annpublic:nB()cout執行B的構造函數endl;nB()cout執行B的析構函數endl;n;nclass C: public Bnnpublic:nC()cout執行C的構造函數endl;nC()cout執行C的析構函數endl;n;nint main()nC c;nreturn 0;nn程序運行結果如下 2. 多繼承如圖12.2(b)所示,類A和類B是C類的基類,它們是多繼承方式,其代碼如下:nclass Annpublic:nA()cout執行A的構造函數endl; nA()c

13、out執行A的析構函數endl; n;nclass B nnpublic:nB()cout執行B的構造函數endl; nB()cout執行B的析構函數endl; n;nclass C: publicB,publicA npublic:nC()cout執行C的構造函數endl;nC()cout執行C的析構函數endl;n;nint main()nnC c;nreturn 0;nn程序運行結果如下:n 執行B的構造函數n 執行A的構造函數n 執行C的構造函數n 執行C的構造函數n 執行A的構造函數n 執行B的構造函數12.3.2 派生類數據成員初始化n一個派生類的構造函數的定義可有下列格式:(形參

14、表)n:基類1(參數表), 基類2(參數表), , 基類n(參數表),n對象成員1(參數表), 對象成員2(參數表), , 對象成員n(參數表)n 成員初始化列表例如,一個長方體類CCuboid,它從基類矩形類CRect派生而來。 基類CRect的數據成員是兩個CPoint類對象ptLT和ptRB,分別表示矩形的左上角點和右下角點的位置。派生類CCuboid自身的數據成員有表示高度的fHeight,表示底面中點位置的CPoint對象ptCenter,如右圖所示。具體程序如下。例Ex_ClassDerived 派生類的構造和析構示例。 n#include nusing namespace std

15、;nclass CPointnnpublic:nCPoint( int x = 0, int y = 0)/ CnnxPos = x;yPos = y;ncoutCPoint構造函數endl;nnvoid ShowPos(bool isEnd = false)nncoutpos(xPos, yPos);nif (isEnd)coutendl;nnprivate:nint xPos, yPos;n;nclass CRectnnpublic:nCRect( int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0)/Bn: ptLT(x1, y1), ptRB(

16、x2, y2)nncoutCRect構造函數endl;nnvoid ShowPos()nnptLT.ShowPos(); cout, ; ptRB.ShowPos(true);nnprivate:nCPoint ptLT, ptRB;n;nclass CCuboid: publicCRectnnpublic:nCCuboid( int x1, int y1, int x2, int y2, int height )/An: CRect(x1, y1, x2, y2),nptCenter(x1+x2)/2, (y1+y2)/2),nfHeight(height)nncoutCCuboid構造函數

17、endl;nnvoid ShowAll()nncout矩形的角點為:;CRect:ShowPos();ncout底面矩形的中點為:;ptCenter.ShowPos(true);ncout高為:fHeightendl;nnprivate:nCPoint ptCenter;nfloatfHeight;n;nint main()nnCCuboid one( 5, 5, 30, 30, 50);none.ShowAll();nreturn 0;nn程序運行結果如下:12.4 二義性和虛基類 n12.4.1 二義性概述n一般來說,在派生類中對基類成員的訪問應該是唯一的。但是多繼承或多層繼承可能造成對基

18、類中某成員的訪問出現不唯一的情況,這種情況稱為基類成員調用的二義性。 n二義性出現的情況可以有下列兩種。n1. 同名成員來源于不同的基類n例Ex_Conflict1同名成員來源于不同的基類 n#include nusing namespace std;nclass Annpublic: n int x;nA(int a = 0) x = a; n;nclass B nnpublic:n int x;nB( int a = 0, int b = 0) x = a; n;nclass C : publicB,publicAnnpublic:nint z;nC(int a, int b, int c

19、)n:A(a), B(b)nnz = c;nn void print()nncoutx = xendl;/編譯出錯的地方ncoutz = zendl;nn;nint main()nnC c1(100,200,300);nc1.print();nreturn 0;n程序中,派生類C同時繼承了A和B這兩個基類,由于基類A和基類B都有數據成員x,當編譯到“coutx = xendl;”語句時,無法確定成員x是來自基類A還是來自基類B,因此產生了二義性,從而出現編譯錯誤。解決這個問題的簡單方法是使用域作用運算符“:”來消除二義性,即將print函數實現代碼改為:nvoid print()nncoutA

20、:x=A:xendl;ncoutB:x=B:xendl;ncoutz = zendl;nn重新運行的結果如下 2. 同名成員來源于同一個基類n例Ex_Conflict2同名成員來源于同一個基類。n#include nusing namespace std;nclass Anpublic: n int x;nA(int a = 0) x = a; n;nclass B1 : public Annpublic:n int y1;nB1( int a = 0, int b = 0)n:A(b)nny1 = a;nn;nclass B2 : public Annpublic:n int y2;nB2(

21、 int a = 0, int b = 0)n:A(b)nny2 = a;nn;nclass C : public B1, public B2nnpublic:nint z;nC(int a, int b, int d, int e, int m)n:B1(a,b), B2(d,e)nnz = m;nn void print()nncoutx = xendl;/ 編譯出錯的地方ncouty1 = y1, y2 = y2endl;ncoutz = zendl;nn;nint main()nnC c1(100,200,300,400,500);nc1.print();nreturn 0;nn程序中

22、,B1類和B2類都是從基類A繼承的派生類,這時在繼承B1和B2的派生類C中就有兩個基類A的拷貝。當編譯器編譯到“coutx = xendl;”語句時,因無法確定成員x是從類B1中繼承來的,還是從類B2繼承來的,因此產生二義性,從而出現了編譯錯誤。n解決這個問題仍可使用前面的方法,即使用域作用運算符“ :”通過指定基類來消除二義性。例如,可將print函數實現代碼改寫為 nvoid print()nncoutB1:x=B1:xendl;ncoutB2:x=B2:xendl;ncouty1 = y1, y2 = y2endl;ncoutz = zendl;nn重新運行后的結果如下:12.4.2 二

23、義性解決方法n(1)當派生類和其基類中都有一個成員X時,在派生類中訪問的X就是派生類的成員X,這是C+中類的局部優先原則。n(2)若A類是B類的基類,B類是C類的基類,當A類和B類都有一個成員X時,則在子類C中訪問的X是B類的成員,這是C+中類的最近優先原則。 n對于出現二義性的第1種情況,指定作用域是最好的解決方法。但對于第2種情況,指定作用域雖是一種解決方法,但不是最好的辦法。因為在派生類C中總有兩個基類A的拷貝,不僅多占用內存,而且效率也不高。為此在實際應用中多采用虛基類的形式來解決。 12.4.3 虛基類和虛繼承n1. 虛基類的定義n虛基類不是指基類是虛的,而是指在派生類中指定的基類是

24、虛繼承方式,即使用下列格式定義派生類的繼承方式:nclass:virtualn;n例Ex_VirtualBase虛基類的使用示例。 n#include nusing namespace std;nclass Annpublic:n int x;nA(int a = 0) x = a; n;nclass B1 : virtual public A/ 聲明虛繼承nnpublic:nint y1;nB1( int a = 0, int b = 0)n:A(b)nny1 = a;nnvoid print(void)nncoutB1: x = x, y1 = y1endl;nn; nclass B2 :

25、 virtual public A/ 聲明虛繼承nnpublic:nint y2;nB2( int a = 0, int b = 0)n:A(b)nny2 = a;nnvoid print(void)nncoutB2: x = x, y2 = y2endl;nn;nclass C : public B1, public B2nnpublic:nint z;nC(int a, int b, int d, int e, int m)n:B1(a,b), B2(d,e)nnz = m;nnvoid print()nnB1:print();B2:print();ncoutz = zendl;nn;ni

26、nt main()nnC c1(100,200,300,400,500);c1.print();nc1.x = 400;c1.print();nreturn 0;nn程序運行結果如下:n2. 虛基類的實質n在上述示例中,類A、B1、B2和C的層次關系可用圖12.5來表示 圖12.5 類的層次關系12.5 兼容n兼容是指在公有派生情況下,一個派生類對象可以賦給基類對象,這種情況又稱為賦值兼容,或稱類型自動轉換。n12.5.1 賦值兼容規則n簡單地講,對于公有派生類來說,可以將派生類的對象直接賦給其基類對象,反之卻不可以。 12.5.2 賦值兼容機理n例Ex_CastTest派生類賦值兼容測試示例

27、。 n#include n#include nusing namespace std;nclass CAnnpublic:nCA(int x = 0) a = x; nint getA() return a; nprivate:nint a;n;nclass CB nnpublic:nCB(int x = 0) b = x; nint getB() return b; nprivate:nint b;n;nclass CC: public CB, public CAnnpublic:nCC( int y = 0) c = y;nint getC() return c; nprivate:nin

28、t c;n;nint main()nnCC *c = new CC(5);ncoutgetC(),getB(),getA()endl;nCA a(3);nCB b(4);nmemcpy(CA*)c,&a,sizeof(a); /Anmemcpy(CB*)c,&b,sizeof(b);/BncoutgetC(),getB(),getA()endl;ndelete c;nreturn 0;nn程序運行結果如下: Ex_CastOther 派生類賦值兼容其他情況示例。 n#include n#include nusing namespace std;nclass CAnnpublic

29、:nCA(int x = 0) a = x; nint getA() return a; nvoid ShowAddr()nncoutCA對象的地址:(unsigned)thisendl;ncoutta的地址:(unsigned)&aendl;nnprivate:nint a;n;nclass CB nnpublic:nCB(intx=0)b=x;nintgetB()returnb;nvoidShowAddr()nncoutCB對象的地址:對象的地址:(unsigned)thisendl;ncouttb的地址:的地址:(unsigned)&bendl;nnprivate:nin

30、tb;n;nclassCC:publicCB,publicCAnnpublic:nCC(inty=0)c=y;nintgetC()returnc;nvoidShowAddr()nnCA:ShowAddr();nCB:ShowAddr();ncoutCC對象的地址:對象的地址:(unsigned)thisendl;ncouttc的地址:的地址:(unsigned)&cendl;nnprivate:nint c;n;nint main()nnCC c(5);/ c對象中的數據成員c為5ncout- CC c(5);-endl;nc.ShowAddr();ncout- CA *a = &c;-ShowAddr();ncout- CB &b = c; -endl;nCB &b = c;/ Bnb.ShowAddr();nb = CB(4);n*a = CA(3);ncoutc.getC(),c.getB(),c.getA()endl;nreturn 0;n程序運行結果如下: 12.6 綜合應用實例n12.6.1 類間關系n1. 繼承關系n2. 組合關系 n3. 共享關系12.6.2 設計實例n例Ex_Multi12綜合應用實例 n#include n#include nusing namespace std;ncla

溫馨提示

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

評論

0/150

提交評論