第16-17章-1-繼承--多態(tài)-虛函數(shù).._第1頁
第16-17章-1-繼承--多態(tài)-虛函數(shù).._第2頁
第16-17章-1-繼承--多態(tài)-虛函數(shù).._第3頁
第16-17章-1-繼承--多態(tài)-虛函數(shù).._第4頁
第16-17章-1-繼承--多態(tài)-虛函數(shù).._第5頁
已閱讀5頁,還剩59頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、16.116.1繼承的概念繼承的概念16.216.2繼承的工作方式繼承的工作方式16.316.3派生類的構(gòu)造派生類的構(gòu)造16.416.4繼承與組合繼承與組合16.516.5多態(tài)性多態(tài)性16.616.6多態(tài)的思考方式多態(tài)的思考方式16.716.7多態(tài)性如何工作多態(tài)性如何工作16.816.8不恰當(dāng)?shù)奶摵瘮?shù)不恰當(dāng)?shù)奶摵瘮?shù)16.916.9虛函數(shù)的限制虛函數(shù)的限制16.1016.10類的冗余類的冗余16.1116.11克服冗余帶來的問題克服冗余帶來的問題16.1216.12類的分解類的分解16.1316.13抽象類抽象類16.1416.14由抽象類派生具體類由抽象類派生具體類16.1516.15純虛函數(shù)

2、的需要性純虛函數(shù)的需要性17.117.1多繼承如何工作多繼承如何工作17.217.2繼承的模糊性繼承的模糊性17.317.3虛擬繼承虛擬繼承17.417.4多繼承的構(gòu)造順序多繼承的構(gòu)造順序17.517.5繼承的訪問控制繼承的訪問控制17.617.6保護繼承與私有繼承保護繼承與私有繼承1u繼承(繼承(inheritanceinheritance): : 一個新類從已有類那里獲得其已有特性一個新類從已有類那里獲得其已有特性( (屬性、行為屬性、行為) )u派生(派生(derivationderivation):):在已有類的基礎(chǔ)上新增自己的特性而產(chǎn)生新類的過程在已有類的基礎(chǔ)上新增自己的特性而產(chǎn)生新

3、類的過程2基類和派生類基類和派生類u 若一個類若一個類C2從另一個類從另一個類C1擴展而來擴展而來,則稱則稱C2為派生類(為派生類(derived class),),C1為基類(為基類(base class)。)。u 基類也稱為父類(基類也稱為父類(parent class), 派生類也稱為擴展類(派生類也稱為擴展類(extended class)或子類()或子類(child class)。)。u 一個派生類繼承了其基類的所有數(shù)據(jù)成員和成員函數(shù)(構(gòu)造函數(shù)一個派生類繼承了其基類的所有數(shù)據(jù)成員和成員函數(shù)(構(gòu)造函數(shù)和析構(gòu)函數(shù)除外),還可以增加新的數(shù)據(jù)成員和函數(shù),從而使派和析構(gòu)函數(shù)除外),還可以增加新

4、的數(shù)據(jù)成員和函數(shù),從而使派生類更具特殊化。生類更具特殊化。u 用指向基類的箭頭表示兩個類之間的繼承關(guān)系。用指向基類的箭頭表示兩個類之間的繼承關(guān)系。C1C1C2C2C3C3C1C1為基類為基類C2C2、C3C3為為C1C1的派生類的派生類345交通工具交通工具火車火車汽車汽車飛機飛機輪船輪船卡車卡車旅行車旅行車小汽車小汽車工具車工具車轎車轎車面包車面包車交通工具分類層次圖交通工具分類層次圖( (單繼承單繼承) )6計算機系人員計算機系人員教職工教職工教務(wù)人員教務(wù)人員學(xué)生學(xué)生教師教師行政管理人員行政管理人員本科生本科生系主任系主任研究生研究生計算機系組成人員的繼承關(guān)系層次圖(多繼承)計算機系組成人

5、員的繼承關(guān)系層次圖(多繼承)7繼承的工作方式繼承的工作方式舉例舉例 (ch16_1.cpp,p350)(ch16_1.cpp,p350)聲明一個派生類,采用不同派生類型,從基類繼承而來的成員的聲明一個派生類,采用不同派生類型,從基類繼承而來的成員的訪問權(quán)限在派生類中也有所不同。訪問權(quán)限在派生類中也有所不同。8l 派生類的繼承方式為公有時,基類各成員在派生類中的訪問權(quán)限:派生類的繼承方式為公有時,基類各成員在派生類中的訪問權(quán)限: 公有成員:公有成員:仍為派生類的公有成員仍為派生類的公有成員 保護成員:保護成員:仍為派生類的保護成員仍為派生類的保護成員 私有成員:私有成員:派生類不能訪問,為基類私

6、有派生類不能訪問,為基類私有l(wèi) 派生類的成員只能訪問基類中的派生類的成員只能訪問基類中的public/protectedpublic/protected成員,不能訪問成員,不能訪問privateprivate成員。成員。l 派生類的對象(在派生類外)只能訪問基類中的派生類的對象(在派生類外)只能訪問基類中的publicpublic成員。成員。l 公有繼承基本保持了基類的訪問屬性,因此使用較多。公有繼承基本保持了基類的訪問屬性,因此使用較多。910直接訪問從基類繼承來的保護成員直接訪問從基類繼承來的保護成員x;基類;基類的私有成員的私有成員y,只能通過接口函數(shù)訪問。,只能通過接口函數(shù)訪問。con

7、st表示該成員函數(shù)不表示該成員函數(shù)不會修改數(shù)據(jù)成員的值會修改數(shù)據(jù)成員的值l 類的派生方式為私有繼承時類的派生方式為私有繼承時 基類的所有基類的所有publicpublic和和protectedprotected的成員在派生類中的訪問權(quán)的成員在派生類中的訪問權(quán)限變?yōu)橄拮優(yōu)閜rivateprivate。即基類的公有成員和保護成員被派生類繼即基類的公有成員和保護成員被派生類繼承過來以后,成為了派生類的私有成員。承過來以后,成為了派生類的私有成員。 基類的私有成員仍為基類的私有成員仍為基類私有基類私有。l 派生類的成員只能訪問基類中的派生類的成員只能訪問基類中的public/protectedpubl

8、ic/protected成員,不能成員,不能訪問訪問privateprivate成員成員l 派生類的對象不能訪問基類中的任何成員派生類的對象不能訪問基類中的任何成員11121314l 當(dāng)類的派生方式為保護繼承時:當(dāng)類的派生方式為保護繼承時: 基類的所有公有基類的所有公有publicpublic和保護和保護protectedprotected的成員在派生類中的的成員在派生類中的訪問權(quán)限變?yōu)樵L問權(quán)限變?yōu)閜rotectedprotected 基類的私有成員仍為基類的私有成員仍為基類私有?;愃接小 基類中的公有和保護成員被派生類繼承過來,作為派生類中的保基類中的公有和保護成員被派生類繼承過來,作為

9、派生類中的保護成員,基類的私有成員在派生類中不能直接使用。護成員,基類的私有成員在派生類中不能直接使用。l 派生類的成員也只能訪問基類中的派生類的成員也只能訪問基類中的public/protectedpublic/protected成員,而不成員,而不能訪問能訪問privateprivate成員。成員。l 派生類的對象不能訪問基類中的任何成員。派生類的對象不能訪問基類中的任何成員。1516u在單個類中,在單個類中,protectedprotected和和privateprivate沒有什么區(qū)別。沒有什么區(qū)別。u但在繼承關(guān)系中,基類的但在繼承關(guān)系中,基類的privateprivate成員不但對應(yīng)

10、用程序隱藏,也對派成員不但對應(yīng)用程序隱藏,也對派生類隱藏。而基類的生類隱藏。而基類的protectedprotected成員只對應(yīng)用程序隱藏,不對派生類隱成員只對應(yīng)用程序隱藏,不對派生類隱藏。藏。保護繼承和私有繼承的區(qū)別保護繼承和私有繼承的區(qū)別 當(dāng)把派生類當(dāng)作基類去派生其他類時會產(chǎn)生不同結(jié)果。當(dāng)把派生類當(dāng)作基類去派生其他類時會產(chǎn)生不同結(jié)果。l用私有繼承方式派生出來的類,從基類派生出來的公有和保用私有繼承方式派生出來的類,從基類派生出來的公有和保護成員被當(dāng)作這個類的私有成員,如果這個類去派生其他類,護成員被當(dāng)作這個類的私有成員,如果這個類去派生其他類,它派生出來的類的成員函數(shù)將無法訪問這些私有成

11、員;它派生出來的類的成員函數(shù)將無法訪問這些私有成員;l采用保護方式派生出來的類采用保護方式派生出來的類, ,從基類中繼承的公有和保護成從基類中繼承的公有和保護成員被當(dāng)作這個類的保護成員,如果用這個類去派生其他類,員被當(dāng)作這個類的保護成員,如果用這個類去派生其他類,它的派生類的成員函數(shù)將可以直接訪問這些成員。它的派生類的成員函數(shù)將可以直接訪問這些成員。171819綜合舉例綜合舉例 (p389p389,繼承的訪問控制),繼承的訪問控制)class Base public: int m1; protected: int m2; private: int m3; ;class PriClass : p

12、rivate Base public: void test( ) m1=1; /ok,將將m1據(jù)為據(jù)為private m2=2; /ok m3=3; /error,不可訪問基類的私有成員不可訪問基類的私有成員 ; 20Class DerivedFromPri : public PriClass public: void test( ) m1=1; /error m2=2; /error m3=3; /error ; int main( ) PriClass priObj: priObj.m1=1; /error priObj.m2=2; /error priObj.m3=3; /error c

13、lass Base public: int m1; protected: int m2; private: int m3; ;class ProClass : protected Base public: void test( ) m1=1; /ok,將將m1據(jù)為據(jù)為protected m2=2; /ok m3=3; /error,不可訪問基類的私有成員不可訪問基類的私有成員 ; 21Class DerivedFromPro : public ProClass public: void test( ) m1=1; /m1仍為仍為protected m2=2; / m2 m2仍為仍為protec

14、tedprotected m3=3; /error,不可訪問,不可訪問 ; int main( ) ProClass proObj: proObj.m1=1; /error proObj.m2=2; /error proObj.m3=3; /error class Base public: int m1; protected: int m2; private: int m3; ;class PubClass : public Base public: void test( ) m1=1; /ok, m1為為public m2=2; /ok,m2為為protected m3=3; /error,

15、不可訪問基類的私有成員不可訪問基類的私有成員 ; 22Class DerivedFromPub : public PubClass public: void test( ) m1=1; /m1仍為仍為public m2=2; / m2 m2仍為仍為protectedprotected m3=3; /error,不可訪問,不可訪問 ; int main( ) PubClass pubObj: pubpubObj.m1=1; pubpubObj.m2=2; /error pubpubObj.m3=3; /error 23繼承中的賦值兼容規(guī)則繼承中的賦值兼容規(guī)則現(xiàn)有一個學(xué)生類現(xiàn)有一個學(xué)生類Stude

16、ntStudent,要增加研究生類,要增加研究生類GraduateStudentGraduateStudent。由于研究生除了他自己特有的性質(zhì)外,還具有學(xué)生的所有性由于研究生除了他自己特有的性質(zhì)外,還具有學(xué)生的所有性質(zhì),所以我們用繼承的方法來重用學(xué)生類。質(zhì),所以我們用繼承的方法來重用學(xué)生類。class Studentclass Student / /;class GraduateStudentclass GraduateStudent: : publicpublic Student Student / /;24void fn(Student & s)void fn(Student &a

17、mp; s) /任何學(xué)生想要做的事情任何學(xué)生想要做的事情 int mainint main()() GraduateStudent gs GraduateStudent gs; fn fn(gsgs);); /fn()/fn()把把gsgs視為視為StudentStudent類對象類對象 GraduateStudentGraduateStudent對象尺寸對象尺寸thisthis指針指針GraduateStudentGraduateStudent的內(nèi)存布局圖的內(nèi)存布局圖l 賦值兼容規(guī)則:是指在需要基類對象的任何地方都可以使用賦值兼容規(guī)則:是指在需要基類對象的任何地方都可以使用公有派生類的對象公

18、有派生類的對象來替代。來替代。通過公有繼承,派生類得到了基類通過公有繼承,派生類得到了基類中除構(gòu)造函數(shù)和析構(gòu)函數(shù)之外的所有成員。這樣公有派生類實中除構(gòu)造函數(shù)和析構(gòu)函數(shù)之外的所有成員。這樣公有派生類實際就具備了基類的所有功能,凡是基類能解決的問題,公有派際就具備了基類的所有功能,凡是基類能解決的問題,公有派生類都可以解決。賦值兼容規(guī)則中所指的替代包括以下情況:生類都可以解決。賦值兼容規(guī)則中所指的替代包括以下情況:派生類的對象可以賦值給基類對象派生類的對象可以賦值給基類對象派生類的對象可以初始化基類的引用派生類的對象可以初始化基類的引用派生類對象的地址可以賦給指向基類對象的指針派生類對象的地址可以

19、賦給指向基類對象的指針l 在替代之后,派生類對象就可以作為基類的對象使用,但只在替代之后,派生類對象就可以作為基類的對象使用,但只能使用從基類繼承的成員。能使用從基類繼承的成員。25由于賦值兼容規(guī)則的引入,對于基類及其公有派生類的對象,可以使用由于賦值兼容規(guī)則的引入,對于基類及其公有派生類的對象,可以使用相同的函數(shù)統(tǒng)一進行處理,而沒有必要為每一個類設(shè)計單獨的模塊,從相同的函數(shù)統(tǒng)一進行處理,而沒有必要為每一個類設(shè)計單獨的模塊,從而提高程序開發(fā)效率。而提高程序開發(fā)效率。class B0class B0 public: public: void display() void display() co

20、ut“B0:display()”endl; cout“B0:display()”endl;class B1: public B0class B1: public B0 public: public: void display() void display() cout“B1:display()”endl; cout“B1:display()”endl;class D1: public B1class D1: public B1 public: public: void display() void display() cout“D1:display()”endl; cout“D1:displa

21、y()”display(); ptr-display(); void main()void main() B0 b0; B0 b0; B1 b1; B1 b1; D1 d1; D1 d1; B0 B0 * *p;p; p=&b0; p=&b0; fun(p); fun(p); p=&b1; p=&b1; fun(p); fun(p); p=&d1; p=&d1; fun(p); fun(p); 26每一個派生類型對應(yīng)的是緊接其后給出的基類名,而且必須給每個基類指定每一個派生類型對應(yīng)的是緊接其后給出的基類名,而且必須給每個基類指定一種派生類型,若缺

22、省,相應(yīng)的基類則取私有派生類型,而不是和前一個基一種派生類型,若缺省,相應(yīng)的基類則取私有派生類型,而不是和前一個基類取相同的派生類型。類取相同的派生類型。272829派生類不能訪問派生類不能訪問基類的私有成員基類的私有成員30例:class Vehicle /車輛類車輛類 /;class Motor /馬達類馬達類 /;class Car : public Vehicle public: Motor motor;31void vehicleFn( Vehicle & v);void motorFn( Motor & m);int main Car c; vehicleFn( c

23、 ) ; /ok motorFn( c ) ; /error,參數(shù)要求是馬達參數(shù)要求是馬達 motorFn( c.motor ) ; /ok;汽車包含有馬達,擁有汽車包含有馬達,擁有一輛汽車同時也擁有一一輛汽車同時也擁有一個馬達個馬達32l 創(chuàng)建對象時要調(diào)用構(gòu)造函數(shù),對象消亡時要調(diào)用析構(gòu)函數(shù)。創(chuàng)建對象時要調(diào)用構(gòu)造函數(shù),對象消亡時要調(diào)用析構(gòu)函數(shù)。l 派生類派生類不繼承不繼承基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。l 在構(gòu)造一個派生類時,完成其基類部分的構(gòu)造由基類的構(gòu)造函數(shù)在構(gòu)造一個派生類時,完成其基類部分的構(gòu)造由基類的構(gòu)造函數(shù)去做。去做。l 在創(chuàng)建派生類對象時在創(chuàng)建派生類對象時,系統(tǒng)

24、要,系統(tǒng)要調(diào)用派生類的構(gòu)造函數(shù),調(diào)用派生類的構(gòu)造函數(shù),在執(zhí)行派在執(zhí)行派生類構(gòu)造函數(shù)生類構(gòu)造函數(shù)( (體體) )前,系統(tǒng)前,系統(tǒng)要先調(diào)用其基類的構(gòu)造函數(shù)要先調(diào)用其基類的構(gòu)造函數(shù)以實現(xiàn)對以實現(xiàn)對從基類繼承的數(shù)據(jù)成員的初始化,再執(zhí)行派生類構(gòu)造函數(shù)體以實從基類繼承的數(shù)據(jù)成員的初始化,再執(zhí)行派生類構(gòu)造函數(shù)體以實現(xiàn)新增成員的初始化?,F(xiàn)新增成員的初始化。l 派生類對象消亡時,派生類對象消亡時,33l 派生類在構(gòu)造時,即使可以直接訪問基類的保護數(shù)據(jù)成員以初派生類在構(gòu)造時,即使可以直接訪問基類的保護數(shù)據(jù)成員以初始化它們,一般也不這么做,而是通過基類的接口函數(shù)去訪問始化它們,一般也不這么做,而是通過基類的接口函數(shù)

25、去訪問它們,初始化也是通過基類的構(gòu)造函數(shù)。這樣,一旦基類實現(xiàn)它們,初始化也是通過基類的構(gòu)造函數(shù)。這樣,一旦基類實現(xiàn)有錯,只要不涉及接口,基類的修改不會影響派生類的操作。有錯,只要不涉及接口,基類的修改不會影響派生類的操作。l 類與類之間,各做各的,以接口作溝通,即使基類與子類也不類與類之間,各做各的,以接口作溝通,即使基類與子類也不例外。例外。class A public: A( ); A( ); void setx(int a)x=a; void sety(int b)y=b; int getx( ) constreturn x; int gety( ) constreturn y; pro

26、tected: int x; private: int y;class B: public A public: B( ); B( ); void setz(int c)z=c; int getz()return z; int getsum( )return x+gety()+z; private: int z;34A:A( ):x(1),y(2) cout調(diào)用類調(diào)用類A的構(gòu)造函數(shù)的構(gòu)造函數(shù)endl;A:A( ) cout調(diào)用類調(diào)用類A的析構(gòu)函數(shù)的析構(gòu)函數(shù)endl;B:B( ):z(3) cout調(diào)用類調(diào)用類B的構(gòu)造函數(shù)的構(gòu)造函數(shù)endl;B:B( ) cout調(diào)用類調(diào)用類B的析構(gòu)函數(shù)的析構(gòu)函數(shù)

27、endl;int main() B b; coutX=b.getx( )tY=b.gety( ) tZ=b.getz( )endl; coutX+Y+Z=b.getsum( )endl; return 0;35派生類名:派生類名(參數(shù)總表)派生類名:派生類名(參數(shù)總表):基類基類1(參數(shù)表(參數(shù)表1),),基類,基類n(參(參數(shù)表數(shù)表n),對象成員),對象成員1(對象成員參數(shù)表(對象成員參數(shù)表1),),對象成員,對象成員n(對象成員參數(shù)(對象成員參數(shù)表表n) 派生類中新聲明的數(shù)據(jù)成員初始化語句派生類中新聲明的數(shù)據(jù)成員初始化語句u對象成員對象成員是指在派生類中新聲明的數(shù)據(jù)成員,它是另外一個類的對

28、象,是指在派生類中新聲明的數(shù)據(jù)成員,它是另外一個類的對象,必須在初始化列表中初始化。必須在初始化列表中初始化。u基類名和對象成員名之間的基類名和對象成員名之間的編寫順序可以是任意的編寫順序可以是任意的,且對于使用默認構(gòu),且對于使用默認構(gòu)造函數(shù)的基類和對象成員,可以不列出基類名和對象成員名。造函數(shù)的基類和對象成員,可以不列出基類名和對象成員名。一般形式如下一般形式如下36參數(shù)總表包括參數(shù)總表包括: 基類數(shù)據(jù)成員、內(nèi)嵌對象數(shù)據(jù)成基類數(shù)據(jù)成員、內(nèi)嵌對象數(shù)據(jù)成員、其他數(shù)據(jù)成員所需的全部數(shù)據(jù)。員、其他數(shù)據(jù)成員所需的全部數(shù)據(jù)。class GraduateStudent : public Student 例

29、:ch16_1.cpp的擴展 public: GraduateStudent (char * pName, Advisor & adv) : Student(pName), advisor(adv) qualifierGrade=0; /其余見ch16_1.cpp;void fn (Advisor & advisor) GraduateStudent gs ( “Kate”, advisor); / int main( ) Advisor da; fn(da);37派生類的構(gòu)造總是由基類的初派生類的構(gòu)造總是由基類的初始化開始的,基類的初始化由始化開始的,基類的初始化由Stude

30、ntStudent(pNamepName)完成。用)完成。用advadv來初始化來初始化advisoradvisor對象成員。對象成員。調(diào)用基類調(diào)用基類StudentStudent的構(gòu)造函數(shù)的構(gòu)造函數(shù)調(diào)用調(diào)用AdvisorAdvisor的構(gòu)造函數(shù)的構(gòu)造函數(shù)最后調(diào)用最后調(diào)用GraduateStudentGraduateStudent的構(gòu)造函數(shù)的構(gòu)造函數(shù)析析構(gòu)構(gòu)class GraduateStudent : public Student public: GraduateStudent (char * pName, Advisor & adv) : advisor(adv), Student

31、(pName) qualifierGrade=0; /其余見ch16_1.cpp;void fn (Advisor & advisor) GraduateStudent gs ( “Kate”, advisor); / int main( ) Advisor da; fn(da);38派生類構(gòu)造開始,仍先調(diào)用基類的構(gòu)造函數(shù)派生類構(gòu)造開始,仍先調(diào)用基類的構(gòu)造函數(shù)Student(pName)Student(pName),若沒有,若沒有Student(pName)Student(pName),則派生類會調(diào)用基類的默認構(gòu)造函數(shù),若找則派生類會調(diào)用基類的默認構(gòu)造函數(shù),若找不到匹配的構(gòu)造函數(shù),就通

32、不過編譯。不到匹配的構(gòu)造函數(shù),就通不過編譯。調(diào)用基類調(diào)用基類StudentStudent的構(gòu)造函數(shù)的構(gòu)造函數(shù)調(diào)用調(diào)用AdvisorAdvisor的構(gòu)造函數(shù)的構(gòu)造函數(shù)最后調(diào)用最后調(diào)用GraduateStudentGraduateStudent的構(gòu)造函數(shù)的構(gòu)造函數(shù)析析構(gòu)構(gòu)39( 4041提示:提示:u 若要將某個類設(shè)計為基類,最好為它設(shè)計一個無參構(gòu)造函數(shù),以若要將某個類設(shè)計為基類,最好為它設(shè)計一個無參構(gòu)造函數(shù),以避免編程錯誤。避免編程錯誤。例:例:class Fruit public:Fruit(int id) ;class Apple : public Fruit public:Apple( )

33、 ;u 由于由于Apple是是Fruit的派生類,的派生類, Apple的構(gòu)造函數(shù)會自動調(diào)用的構(gòu)造函數(shù)會自動調(diào)用Fruit的無參構(gòu)造函數(shù),但是的無參構(gòu)造函數(shù),但是Fruit沒有無實參構(gòu)造函數(shù),因此會產(chǎn)生沒有無實參構(gòu)造函數(shù),因此會產(chǎn)生一個編譯錯誤。一個編譯錯誤。42434445 在派生類中,可以定義同基類中的成員同名的成員,此時:在派生類中,可以定義同基類中的成員同名的成員,此時:u在派生類中基類的同名成員被屏蔽。在派生類中基類的同名成員被屏蔽。u若在派生類中訪問基類被屏蔽的同名成員,則若在派生類中訪問基類被屏蔽的同名成員,則必須使用作必須使用作用域運算符用域運算符:以明確指定其所屬的類,來消除

34、二義性。以明確指定其所屬的類,來消除二義性。 基類名基類名:基類同名數(shù)據(jù)成員基類同名數(shù)據(jù)成員 基類名基類名:基類同名成員函數(shù)基類同名成員函數(shù)(實參列表實參列表)464748495051l 多態(tài):多態(tài):不同的對象接受到相同的消息時產(chǎn)生不同的響應(yīng)動作,不同的對象接受到相同的消息時產(chǎn)生不同的響應(yīng)動作,即對應(yīng)相同的函數(shù)名,卻執(zhí)行了不同的函數(shù)體即對應(yīng)相同的函數(shù)名,卻執(zhí)行了不同的函數(shù)體( (函數(shù)體是事先定函數(shù)體是事先定義好的義好的) )。l 多態(tài)性多態(tài)性(PolymorphismPolymorphism ,源于希臘語,含義為,源于希臘語,含義為“多種形式多種形式”) )是面向?qū)ο蟪绦蛟O(shè)計的關(guān)鍵技術(shù)之一。利

35、用多態(tài)性技術(shù),可以是面向?qū)ο蟪绦蛟O(shè)計的關(guān)鍵技術(shù)之一。利用多態(tài)性技術(shù),可以調(diào)用調(diào)用同一個函數(shù)名同一個函數(shù)名的函數(shù),實現(xiàn)完全不同的功能。的函數(shù),實現(xiàn)完全不同的功能。52C+C+允許子類的成員函數(shù)允許子類的成員函數(shù)重載重載基類的成員函數(shù)。基類的成員函數(shù)。53例如:例如:class Studentclass Student public: public: float calcTuition( )float calcTuition( ) / /計算學(xué)費計算學(xué)費 / / ;class GraduateStudent: public Studentclass GraduateStudent: public

36、Student public: public: float calcTuition( )float calcTuition( ) / / ;int main( )int main( ) Student s;Student s;GraduateStudent gs;GraduateStudent gs;s.calcTuition( ); s.calcTuition( ); /調(diào)用調(diào)用Student:calcTuition( );Student:calcTuition( );gs.calcTuition( ); gs.calcTuition( ); /調(diào)用調(diào)用GraduateStudent:cal

37、cTuition( );GraduateStudent:calcTuition( ); calcTuition( )calcTuition( )呈多態(tài)呈多態(tài)54先期聯(lián)編(先期聯(lián)編(early bindingearly binding):又稱靜態(tài)聯(lián)編,是指編:又稱靜態(tài)聯(lián)編,是指編譯時就能確定哪個重載函數(shù)被調(diào)用。譯時就能確定哪個重載函數(shù)被調(diào)用。遲后聯(lián)編(遲后聯(lián)編(late bindinglate binding): : 又稱動態(tài)聯(lián)編或滯后聯(lián)又稱動態(tài)聯(lián)編或滯后聯(lián)編,是指在程序運行時依據(jù)其類型確認調(diào)用哪個函數(shù)編,是指在程序運行時依據(jù)其類型確認調(diào)用哪個函數(shù)的能力。的能力。多態(tài)技術(shù)的優(yōu)勢:例,教材多態(tài)技術(shù)

38、的優(yōu)勢:例,教材p357p357從實現(xiàn)從實現(xiàn)的角度,的角度,C+中中的兩種的兩種多態(tài)性多態(tài)性 編譯時的多態(tài)編譯時的多態(tài) 運行時的多態(tài)運行時的多態(tài) 程序執(zhí)行前,無法根據(jù)函數(shù)名和參數(shù)來程序執(zhí)行前,無法根據(jù)函數(shù)名和參數(shù)來確定該調(diào)用哪個函數(shù)。必須在程序執(zhí)行確定該調(diào)用哪個函數(shù)。必須在程序執(zhí)行過程中,根據(jù)執(zhí)行的具體情況來過程中,根據(jù)執(zhí)行的具體情況來動態(tài)地動態(tài)地確定。通過類繼承關(guān)系和虛函數(shù)來實現(xiàn)。確定。通過類繼承關(guān)系和虛函數(shù)來實現(xiàn)。在編譯的過程中確定了同名操作的具體在編譯的過程中確定了同名操作的具體操作對象。通過函數(shù)的重載和運算符的操作對象。通過函數(shù)的重載和運算符的重載來實現(xiàn)。重載來實現(xiàn)。l 虛函數(shù)是動態(tài)聯(lián)

39、編的基礎(chǔ),虛函數(shù)經(jīng)過派生之后,在類族中就虛函數(shù)是動態(tài)聯(lián)編的基礎(chǔ),虛函數(shù)經(jīng)過派生之后,在類族中就可以實現(xiàn)運行時多態(tài)??梢詫崿F(xiàn)運行時多態(tài)。l 根據(jù)賦值兼容規(guī)則,可使用派生類的對象代替基類對象。如果根據(jù)賦值兼容規(guī)則,可使用派生類的對象代替基類對象。如果用基類類型的指針指向派生類的對象,就可以通過這個指針來用基類類型的指針指向派生類的對象,就可以通過這個指針來訪問該對象,但只能訪問從基類繼承來的成員。訪問該對象,但只能訪問從基類繼承來的成員。l 如果需要通過基類的指針指向派生類的對象,并訪問某個與基如果需要通過基類的指針指向派生類的對象,并訪問某個與基類同名的函數(shù)成員,可以在基類中將這個同名函數(shù)說明為

40、虛函類同名的函數(shù)成員,可以在基類中將這個同名函數(shù)說明為虛函數(shù)。這樣,通過基類類型的指針,就可以使屬于不同派生類的數(shù)。這樣,通過基類類型的指針,就可以使屬于不同派生類的不同對象產(chǎn)生不同的行為,從而實現(xiàn)運行時多態(tài)。不同對象產(chǎn)生不同的行為,從而實現(xiàn)運行時多態(tài)。虛函數(shù)虛函數(shù)為指明某個成員函數(shù)具有多態(tài)性,要在類的聲明中使用關(guān)為指明某個成員函數(shù)具有多態(tài)性,要在類的聲明中使用關(guān)鍵字鍵字virtualvirtual限定該成員函數(shù),將其標志其為虛函數(shù)。限定該成員函數(shù),將其標志其為虛函數(shù)。 virtual virtual 返回類型返回類型 函數(shù)名(參數(shù)表)函數(shù)名(參數(shù)表) ;55虛函數(shù)虛函數(shù)l關(guān)鍵字關(guān)鍵字virt

41、ualvirtual指明該成員函數(shù)為虛函數(shù)。指明該成員函數(shù)為虛函數(shù)。virtualvirtual僅用于類僅用于類的聲明內(nèi)部的成員函數(shù)原型聲明或定義中,的聲明內(nèi)部的成員函數(shù)原型聲明或定義中,如果成員函數(shù)定義如果成員函數(shù)定義在類外,在類外,virtual只能加在函數(shù)聲明前面,不能加在函數(shù)定義前只能加在函數(shù)聲明前面,不能加在函數(shù)定義前面。面。l當(dāng)一個類的某個成員函數(shù)被聲明為當(dāng)一個類的某個成員函數(shù)被聲明為virtualvirtual,則由該類派生出,則由該類派生出來的所有子類中,該函數(shù)始終保持虛函數(shù)的特征。來的所有子類中,該函數(shù)始終保持虛函數(shù)的特征。( (自動向下帶自動向下帶給其子類給其子類) )。l

42、若未加關(guān)鍵字若未加關(guān)鍵字virtualvirtual,則是派生類中的新成員函數(shù)覆蓋基類,則是派生類中的新成員函數(shù)覆蓋基類同名成員函數(shù)(參數(shù)表必須一樣,否則是重載),可稱為同名同名成員函數(shù)(參數(shù)表必須一樣,否則是重載),可稱為同名覆蓋函數(shù),它不能實現(xiàn)運行時的多態(tài)性。覆蓋函數(shù),它不能實現(xiàn)運行時的多態(tài)性。l虛函數(shù)實例:虛函數(shù)實例:ch16_2.cppch16_2.cpp, ch16_3.cpp ch16_3.cpp5657/ch16_3.cpp/ch16_3.cpp#include#include#include#includeclass Shapeclass Shape public: publi

43、c: Shape(double x, double y) : Shape(double x, double y) : xCoord(x), yCoord(y) xCoord(x), yCoord(y) virtual virtual double Area( ) const double Area( ) const return 0.0; return 0.0; protected:protected: double xCoord, yCoord; double xCoord, yCoord;class Circle :public Shapeclass Circle :public Shap

44、e public: public: Circle(double x, double y, double r) Circle(double x, double y, double r) : Shape(x, y), radius(r) : Shape(x, y), radius(r) virtual virtual double Area( ) const double Area( ) const return 3.14 return 3.14* *radiusradius* *radius; radius; protected: protected: double radius; double

45、 radius;class Rectangle: public Shapeclass Rectangle: public Shape public: public: Rectangle(double x1, double y1, Rectangle(double x1, double y1, double x2, double y2): Shape(x1,y1), double x2, double y2): Shape(x1,y1), x2Coord(x2), y2Coord(y2) x2Coord(x2), y2Coord(y2) virtualvirtual double Area( )

46、 const; double Area( ) const; protected: protected: double x2Coord, y2Coord; double x2Coord, y2Coord;double Rectangle:Area( ) constdouble Rectangle:Area( ) const return return fabs(xCoord-x2Coord) fabs(xCoord-x2Coord)* *(yCoord-y2Coord);(yCoord-y2Coord); void void funfun(const Shape & sp)(const

47、Shape & sp) cout sp.Area() endl; cout sp.Area() endl; void main()void main() Circle c(2.0, 5.0, 4.0) ; Circle c(2.0, 5.0, 4.0) ; fun(c); fun(c); Rectangle t(2.0, 4.0, 1.0, 2.0); Rectangle t(2.0, 4.0, 1.0, 2.0); fun(t); fun(t); 58使用虛函數(shù)的注意事項使用虛函數(shù)的注意事項l當(dāng)在派生類中重新定義虛函數(shù)(覆蓋)時,不必加關(guān)鍵字當(dāng)在派生類中重新定義虛函數(shù)(覆蓋)時,不必

48、加關(guān)鍵字virtualvirtual。但重新定義時。但重新定義時不僅不僅要同名,要同名,而且而且它的參數(shù)表和返回它的參數(shù)表和返回類型全部與基類中的虛函數(shù)一樣,否則出錯。類型全部與基類中的虛函數(shù)一樣,否則出錯。l如果虛函數(shù)在基類與子類中出現(xiàn)的僅僅是名字相同,而參如果虛函數(shù)在基類與子類中出現(xiàn)的僅僅是名字相同,而參數(shù)不同,或返回類型不同,即使寫上了關(guān)鍵字數(shù)不同,或返回類型不同,即使寫上了關(guān)鍵字virtual,也被,也被認為是重載,而不是虛函數(shù),不進行遲后聯(lián)編。認為是重載,而不是虛函數(shù),不進行遲后聯(lián)編。例如,下列程序中,在派生類中重載了基類的成員函數(shù),盡例如,下列程序中,在派生類中重載了基類的成員函數(shù)

49、,盡管標上了管標上了virtual,但運行中起不到多態(tài)效果:,但運行中起不到多態(tài)效果: ch16_4.cpp ch16_4.cppl(特例)若基類中的虛函數(shù)返回一個基類指針或引用,子(特例)若基類中的虛函數(shù)返回一個基類指針或引用,子類中的虛函數(shù)返回一個子類的指針或引用,則類中的虛函數(shù)返回一個子類的指針或引用,則c+將其視為同將其視為同名虛函數(shù),進行遲后聯(lián)編。名虛函數(shù),進行遲后聯(lián)編。例如,例如, ch16_5.cpp59/ ch16_5.cpp/ ch16_5.cpp#include #include class Baseclass Base public: public: virtual Ba

50、se virtual Base * * afn() afn() cout This is Base class.n; cout This is Base class.n; return this; return this; ;class SubClass: public Baseclass SubClass: public Base public: public: SubClass SubClass * * afn() afn() /實際是虛函數(shù)實際是虛函數(shù) cout This is SubClass.n; cout This is SubClass.n; return this; return this; ;void test(Base& x)void test(Base& x) Base Base* * b; b; b = x.afn(); b = x.afn(); /遲后聯(lián)編遲后聯(lián)編 voi

溫馨提示

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

評論

0/150

提交評論