繼承與派生課件_第1頁
繼承與派生課件_第2頁
繼承與派生課件_第3頁
繼承與派生課件_第4頁
繼承與派生課件_第5頁
已閱讀5頁,還剩43頁未讀, 繼續免費閱讀

下載本文檔

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

文檔簡介

C++面向對象程序設計普通高等教育“十一五”國家級規劃教材中國高等院校計算機基礎教育課程體系規劃教材

1第11講繼承與派生11.1授課內容繼承與派生的應用。主要內容:1.多重繼承;2.虛基類;3.繼承與派生的應用。2第11講繼承與派生11.2授課要求(1)理解多重繼承的含義、定義方法和實現;(2)理解虛基類及其作用。3第11講繼承與派生

11.3授課重點1.重點是多重繼承和派生類的應用。11.4授課難點1.難點是派生類的應用。41.多重繼承前面討論了單繼承,即一個類是從一個基類派生而來的。實際上,常常有這樣的情況:一個派生類有兩個或多個基類,派生類從兩個或多個基類中繼承所需的屬性。多重繼承:允許一個派生類同時繼承多個基類。這種行為稱為多重繼承(multipleinheritance)。5(1)聲明多重繼承的方法方法:在單繼承的基礎上,依次列出多個基類。比如:如果已聲明了類A、類B和類C,可以聲明多重繼承的派生類D:classD:publicA,privateB,protectedC{類D新增加的成員}D按不同的繼承方式的規則繼承A,B,C的屬性,確定各基類的成員在派生類中的訪問權限。6(2)多重繼承派生類的構造函數多重繼承派生類的構造函數形式與單繼承時的構造函數形式基本相同,只是在初始表中包含多個基類構造函數。如:派生類構造函數名(總參數表列):

基類1構造函數(參數表列),

基類2構造函數(參數表列),

基類3構造函數

(參數表列)

{派生類中新增數成員據成員初始化語句}派生類構造函數的執行順序為:

先調用基類的構造函數,再執行派生類構造函數的函數體。調用基類構造函數的順序是按照聲明派生類時基類出現的順序。排列順序任意7(2)多重繼承派生類的構造函數例1(P176的例5.8)聲明一個教師(Teacher)類和一個學生(Student)類,用多重繼承的方式聲明一個研究生(Graduate)派生類。

教師類中包括數據成員name(姓名)、age(年齡)、title(職稱)。

學生類中包括數據成員name1(姓名)、age(性別)、score(成績)。在定義派生類對象時給出初始化的數據,然后輸出這些數據。8(2)多重繼承派生類的構造函數#include<iostream>#include<string>usingnamespacestd;classTeacher//聲明類Teacher(教師){public://公用部分

Teacher(stringnam,inta,stringt)//構造函數

{name=nam;age=a;title=t;}voiddisplay()//輸出教師有關數據

{cout<<″name:″<<name<<endl;cout<<″age″<<age<<endl;cout<<″title:″<<title<<endl;}protected://保護部分

stringname;intage;stringtitle;//職稱};12139(2)多重繼承派生類的構造函數classStudent//定義類Student(學生){public:Student(charnam[],chars,floatsco){strcpy(name1,nam);sex=s;score=sco;}//構造函數

voiddisplay1()//輸出學生有關數據

{cout<<″name:″<<name1<<endl;cout<<″sex:″<<sex<<endl;cout<<″score:″<<score<<endl;}protected://保護部分

stringname1;charsex;floatscore;//成績

};121310(2)多重繼承派生類的構造函數classGraduate:publicTeacher,publicStudent

//聲明多重繼承的派生類Graduate{public:

Graduate(stringnam,inta,chars,stringt,floatsco,floatw):

Teacher(nam,a,t),Student(nam,s,sco),wage(w){}

voidshow()//輸出研究生的有關數據

{cout<<″name:″<<name<<endl;cout<<″age:″<<age<<endl;cout<<″sex:″<<sex<<endl;cout<<″score:″<<score<<endl;cout<<″title:″<<title<<endl;cout<<″wages:″<<wage<<endl;}private:

floatwage;//工資

};1211(2)多重繼承派生類的構造函數intmain(){Graduategrad1(″Wang-li″,24,′f′,″assistant″,89.5,1234.5);

grad1.show();return0;}程序運行結果如下:name:Wang-liage:24sex:fscore:89.5title:assistancewages:1234.51112(2)多重繼承派生類的構造函數注意:在兩個基類中分別用name和name1來代表姓名,其實這是同一個人的名字。在兩個基類中都使用同一個數據成員名name?10在show函數中引用數據成員時指明其作用域,如:cout<<″name:″<<Teacher::name<<endl;這就是唯一的,不致引起二義性的方法。可以發現一個問題:在多重繼承時,從不同的基類中會繼承一些重復的數據。如果有多個基類,問題會更突出。在設計派生類時要細致考慮其數據成員,盡量減少數據冗余。13(3)多重繼承引起的二義性問題這些重復的數據或者同名的成員使用不當,則:會產生的二義性(ambiguous)問題。進一步討論:如果類A和類B中都有成員函數display和數據成員a,類C是類A和類B的直接派生類。分別討論下列3種情況:(a)兩個基類有同名成員。如圖1所示。查看如下程序:圖114(3)多重繼承引起的二義性問題classA{public:inta;voiddisplay();};classB{public:inta;voiddisplay();};classC:publicA,publicB{public:intb;voidshow();};intmain(){Cc1;

c1.a=3;c1.display();return0;}因為:編譯系統無法判別要訪問的是哪一基類的成員c1.A::a=3;c1.A::display();程序編譯出錯15(3)多重繼承引起的二義性問題為清楚起見,圖1應改用圖2的形式表示。圖216(3)多重繼承引起的二義性問題(b)兩個基類和派生類三者都有同名成員。將上面的C類聲明改為classC:publicA,publicB{inta;voiddisplay();};如圖3所示。即有3個a,3個display函數。圖317(3)多重繼承引起的二義性問題如果:intmain(){Cc1;

c1.a=3;c1.display();return0;}程序能通過編譯,也可正常運行。訪問的是派生類C中的成員。訪問同名成員的規則:

基類的同名成員在派生類中被屏蔽,成為“不可見”的,或者說,派生類新增加的同名成員覆蓋了基類中的同名成員。18(3)多重繼承引起的二義性問題請注意:

①不同的成員函數,只有在函數名和參數個數相同、類型相匹配的情況下才發生同名覆蓋,如果只有函數名相同而參數不同,不會發生同名覆蓋,而屬于函數重載。②要在派生類外訪問基類A中的成員,應指明作用域A,寫成以下形式:c1.A::a=3;//表示是派生類對象c1中的基類A中的數據成員ac1.A::display();//表示是派生類對象c1中的基類A中的成員函數display19(3)多重繼承引起的二義性問題(c)如果類A和類B是從同一個基類派生的,如圖4所示。classN{public:inta;voiddisplay(){cout<<″A::a=”<<a<<endl;}};classA:publicN{public:inta1;};classB:publicN{public:inta2;};圖4classC:publicA,publicB{public:inta3;};20(3)多重繼承引起的二義性問題怎樣才能訪問類A中從基類N繼承下來的成員呢?應當通過類N的直接派生類名來指出要訪問的是類N的哪一個派生類中的基類成員。如:c1.A::a=3;c1.A::display();c1.a=3;c1.display();或c1.N::a=3;c1.N::display();×顯然不行!因為這樣依然無法區別是類A中從基類N繼承下來的成員,還是類B中從基類N繼承下來的成員。21(4)虛基類從上面的介紹可知:如果一個派生類有多個直接基類,而這些直接基類又有一個共同的基類,則在最終的派生類中會保留該間接共同基類數據成員的多份同名成員。如圖7和圖8所示。22(4)虛基類圖7圖8在引用這些同名的成員時,必須在派生類對象名后增加直接基類名,以避免產生二義性。如:c1.A::display()。23(4)虛基類在一個類中保留間接共同基類的多份同名成員,這種現象是人們不希望出現的。a.虛基類的作用C++提供虛基類(virtualbaseclass)的方法,使得在繼承間接共同基類時只保留一份成員。聲明虛基類的一般形式為:class派生類名:virtual

繼承方式基類名24(4)虛基類現在,將類A聲明為虛基類,方法如下:

classA//聲明基類A{…};classB:virtualpublicA//聲明類B是類A的公用派生類,A是B的虛基類

{…};classC:virtualpublicA//聲明類C是類A的公用派生類,A是C的虛基類

{…};注意:虛基類并不是在聲明基類時聲明的,而是在聲明派生類時,指定繼承方式時聲明的。25(4)虛基類經過這樣的聲明后,當基類通過多條派生路徑被一個派生類繼承時,該派生類只繼承該基類一次。D類intdata;intdata_b;intdata_cvoidfun();intdata_d;voidfun_d();26(4)虛基類b.虛基類的初始化如果在虛基類中定義了帶參數的構造函數,而且沒有定義默認構造函數,則在其所有派生類(包括直接派生或間接派生的派生類)中,通過構造函數的初始化表對虛基類進行初始化。例如classA//定義基類A{A(inti){}//基類構造函數,有一個參數……};classB:virtualpublicA//A作為B的虛基類

{B(intn):A(n){}//B類構造函數,在初始化表中對虛基類初始化…};classC:virtualpublicA//A作為C的虛基類{C(intn):A(n){}//C類構造函數,在初始化表中對虛基類初始化…};classD:publicB,publicC//類D的構造函數,在初始化表中對所有基類初始化

{D(intn):A(n),B(n),C(n){}…};27(4)虛基類注意:在定義類D的構造函數時,與以往使用的方法有所不同。規定:在最后的派生類中不僅要負責對其直接基類進行初始化,還要負責對虛基類初始化。C++編譯系統只執行最后的派生類對虛基類的構造函數的調用,而忽略虛基類的其他派生類(如類B和類C)對虛基類的構造函數的調用,這就保證了虛基類的數據成員不會被多次初始化。282.虛基類的簡單應用舉例例2(P185例5.9)在例5.8(P176)的基礎上,在Teacher類和Student類之上增加一個共同的基類Person,如所示。作為人員的一些基本數據都放在Person中,在Teacher類和Student類中再增加一些必要的數據。圖11292.虛基類的簡單應用舉例#include<iostream>#include<string>usingnamespacestd;//聲明公共基類PersonclassPerson{public:Person(stringnam,chars,inta)//構造函數

{name=nam;sex=s;age=a;}protected://保護成員

stringname;charsex;intage;};302.虛基類的簡單應用舉例//聲明Person的直接派生類TeacherclassTeacher:virtualpublicPerson

//聲明Person為公用繼承的虛基類{public:Teacher(stringnam,chars,inta,stringt):Person(nam,s,a)//構造函數

{title=t;}protected://保護成員

stringtitle;//職稱};312.虛基類的簡單應用舉例//聲明Person的直接派生類StudentclassStudent:virtualpublicPerson

//聲明Person為公用繼承的虛基類{public:Student(stringnam,chars,inta,floatsco)//構造函數

:Person(nam,s,a),score(sco){}//初始化表protected://保護成員

floatscore;//成績

};322.虛基類的簡單應用舉例classGraduate:publicTeacher,publicStudent//Teacher和Student為直接基類{public:Graduate(stringnam,chars,inta,stringt,floatsco,floatw):Person(nam,s,a),Teacher(nam,s,a,t),Student(nam,s,a,sco),wage(w){}voidshow()//輸出研究生的有關數據

{cout<<″name:″<<name<<endl;cout<<″age:″<<age<<endl;cout<<″sex:″<<sex<<endl;cout<<″score:″<<score<<endl;cout<<″title:″<<title<<endl;cout<<″wages:″<<wage<<endl;}private:floatwage;//工資

};332.虛基類的簡單應用舉例//主函數intmain(){Graduategrad1(″Wang-li″,′f′,24,″assistant″,89.5,1234.5);grad1.show();return0;}運行結果為name:Wang-liage:24sex:fscore:89.5title:assistantwages:1234.5342.虛基類的簡單應用舉例可以看到:使用多重繼承時要十分小心,經常會出現二義性問題。許多專業人員認為:

不要提倡在程序中使用多重繼承,只有在比較簡單和不易出現二義性的情況或實在必要時才使用多重繼承,能用單一繼承解決的問題就不要使用多重繼承。也是由于這個原因,有些面向對象的程序設計語言(如Java,Smalltalk)并不支持多重繼承。35***3.基類與派生類的轉換由于派生類中包含從基類繼承的成員,因此可以將派生類的值賦給基類對象,在用到基類對象的時候可以用其子類對象代替。具體表現在以下幾個方面:(a)派生類對象可以向基類對象賦值??梢杂米宇?即公用派生類)對象對其基類對象賦值。如Aa1;//定義基類A對象a1Bb1;//定義類A的公用派生類B的對象b1a1=b1;//用派生類B對象b1對基類對象a1賦值在賦值時舍棄派生類自己的成員。36***3.基類與派生類的轉換實際上,所謂賦值只是對數據成員賦值,對成員函數不存在賦值問題。注意:

賦值后不能企圖通過對象a1去訪問派生類對象b1的成員,因為b1的成員與a1的成員是不同的。特別注意:只能用子類對象對其基類對象賦值,而不能用基類對象對其子類對象賦值。因為基類對象不包含派生類的成員,無法對派生類的成員賦值。同理,同一基類的不同派生類對象之間也不能賦值。Aa1;Bb1;//B是A的公用派生a1=b1;37***3.基類與派生類的轉換(b)派生類對象可以替代基類對象,向基類對象的引用進行賦值或初始化。如已定義了基類A對象a1,可以定義a1的引用變量:Aa1;//定義基類A對象a1Bb1;//定義公用派生類B對象b1A&r=a1;//定義基類A對象的引用變量r,并用a1對其初始化這時,引用變量r是a1的別名,r和a1共享同一段存儲單元。若:A&r=b1;//定義基類A對象的引用變量r,并用派生類B對象b1對其初始化或者保留上面第3行“A&r=a1;”,而對r重新賦值:r=b1;注意:

此時r并不是b1的別名,也不與b1共享同一段存儲單元。它只是b1中基類部分的別名,r與b1中基類部分共享同一段存儲單元,r與b1具有相同的起始地址。38***3.基類與派生類的轉換(c)如果函數的參數是基類對象或基類對象的引用,相應的實參可以用子類對象。如有一函數fun:voidfun(A&r)//形參是類A的對象的引用變量

{cout<<r.num<<endl;}函數的形參是類A的對象的引用變量,本來實參應該為A類的對象。在調用fun函數時可以用派生類B的對象b1作實參:

fun(b1);//(假設B是A的派生類)則結果:輸出類B的對象b1的基類數據成員num的值。39***3.基類與派生類的轉換(d)派生類對象的地址可以賦給指向基類對象的指針變量,也就是說,指向基類對象的指針變量也可以指向派生類對象。比如:(參見189例5.10)classStudent//聲明Student類{public:Student(int,string,float);voiddisplay();private:intnum;stringname;floatscore;};classGraduate:publicStudent{public:Graduate(int,string,float,float);voiddisplay();private:floatpay;//工資};40***3.基類與派生類的轉換voidStudent::display()//定義輸出函數{cout<<endl<<″num:″<<num<<endl;cout<<″name:″<<name<<endl;cout<<″score:″<<score<<endl;}voidGraduate::display()//定義輸出函數{Student::display();//調用Student類的display函數

cout<<″pay=″<<pay<<endl;}4241***3.基類與派生類的轉換intmain(){Studentstud1(1001,″Li″,87.5);Graduategrad1(2001,″Wang″,98.5,563.5);Student*pt=&stud1;//定義指向Student類對象的指針并指向stud1pt->display();//調用stud1.display函數

pt=&grad1;//指針指向grad1pt->display();//調用grad1.display函數

}通過指向基類對象的指針,只能訪問派生類中的基類成員,而不能訪問派生類增加的成員num:1001name:Liscore:87.5num:2001name:wangscore:98.541需要訪問,使用虛函數和多

溫馨提示

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

評論

0/150

提交評論