![第十七章多重繼承_第1頁(yè)](http://file4.renrendoc.com/view/006ecde87aa349d468cca225f65b0397/006ecde87aa349d468cca225f65b03971.gif)
![第十七章多重繼承_第2頁(yè)](http://file4.renrendoc.com/view/006ecde87aa349d468cca225f65b0397/006ecde87aa349d468cca225f65b03972.gif)
![第十七章多重繼承_第3頁(yè)](http://file4.renrendoc.com/view/006ecde87aa349d468cca225f65b0397/006ecde87aa349d468cca225f65b03973.gif)
![第十七章多重繼承_第4頁(yè)](http://file4.renrendoc.com/view/006ecde87aa349d468cca225f65b0397/006ecde87aa349d468cca225f65b03974.gif)
![第十七章多重繼承_第5頁(yè)](http://file4.renrendoc.com/view/006ecde87aa349d468cca225f65b0397/006ecde87aa349d468cca225f65b03975.gif)
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第十七章多重繼承第一頁(yè),共八十三頁(yè),編輯于2023年,星期五2本章主要內(nèi)容多繼承如何工作多繼承的構(gòu)造順序繼承的模糊性(二義性問(wèn)題)虛基類(lèi)保護(hù)繼承與私有繼承第二頁(yè),共八十三頁(yè),編輯于2023年,星期五3在現(xiàn)實(shí)世界中存在一個(gè)類(lèi)是由多個(gè)類(lèi)派生的情況。兩用沙發(fā),它是一個(gè)沙發(fā),也是一個(gè)床。兩用沙發(fā)應(yīng)允許同時(shí)繼承沙發(fā)和床的特征。第三頁(yè),共八十三頁(yè),編輯于2023年,星期五4多繼承時(shí)派生類(lèi)的定義class派生類(lèi)名:繼承方式1基類(lèi)名1,
繼承方式2基類(lèi)名2,...{
成員定義;}注意:每一個(gè)“繼承方式”,只用于限制對(duì)緊隨其后之基類(lèi)的繼承。第四頁(yè),共八十三頁(yè),編輯于2023年,星期五5,所討論的類(lèi)層次中,每個(gè)類(lèi)只繼承一個(gè)父輩,在現(xiàn)實(shí)世界中事情通常是這樣的。但是一些類(lèi)卻代表兩個(gè)類(lèi)的合成。例如,兩用沙發(fā),它是一個(gè)沙發(fā),也是一張床,兩用沙發(fā)應(yīng)允許同時(shí)繼承沙發(fā)和床的特征,即SleeperSofa繼承Bed和Sofa兩個(gè)類(lèi),如圖所示。其程序代碼如下:兩用沙發(fā)的類(lèi)層次第五頁(yè),共八十三頁(yè),編輯于2023年,星期五6classBed{public: Bed():weight(0){} voidSleep(){cout<<"Sleeping...\n";} voidSetWeight(inti){weight=i;}protected: intweight;};classSofa{public: Sofa():weight(0){} voidWatchTV(){cout<<"WatchingTV.\n";} voidSetWeight(inti){weight=i;}protected: intweight;};第六頁(yè),共八十三頁(yè),編輯于2023年,星期五7classSleeperSofa:publicBed,publicSofa{public: SleeperSofa(){} voidFoldOut(){cout<<"Foldoutthesofa.\n";}};voidmain(){ SleeperSofass; ss.WatchTV(); ss.FoldOut(); ss.Sleep(); cin.get();}
第七頁(yè),共八十三頁(yè),編輯于2023年,星期五8運(yùn)行結(jié)果為:
WatchingTV.
Foldoutthesofa.
Sleeping...兩用沙發(fā)繼承兩個(gè)基類(lèi)的所有成員,這樣ss.Sleep()和ss.WmchTV()的調(diào)用是合法的。也就可以把SleeperSofa)fa當(dāng)作一個(gè)Bed或一個(gè)Sofa用。另外,SleeperSoa類(lèi)還有它自己的成員FoldOut()。第八頁(yè),共八十三頁(yè),編輯于2023年,星期五9多繼承舉例classA{public:voidsetA(int);voidshowA();private:inta;};classB{public:voidsetB(int);voidshowB();private:intb;};classC:publicA,privateB{public:voidsetC(int,int,int);voidshowC();private:intc;};第九頁(yè),共八十三頁(yè),編輯于2023年,星期五voidA::setA(intx){a=x;}voidB::setB(intx){b=x;}voidC::setC(intx,inty,intz){SetA(x);SetB(y);c=z;}//其它函數(shù)實(shí)現(xiàn)略intmain(){Cobj;obj.setA(5);obj.showA();obj.setC(6,7,9);obj.showC();obj.setB(6);obj.showB();return0;}//error//error第十頁(yè),共八十三頁(yè),編輯于2023年,星期五11本章主要內(nèi)容多繼承如何工作繼承的模糊性(二義性問(wèn)題)多繼承的構(gòu)造順序虛基類(lèi)第十一頁(yè),共八十三頁(yè),編輯于2023年,星期五12Sofa和Bed都有一個(gè)成員weight,這是合理的,因?yàn)閮烧叨际菍?shí)體,都有一個(gè)重量。問(wèn)題是SleeperSofa繼承哪個(gè)重量?既然兩者都繼承,由于兩者有相同的名字weight,使得對(duì)weight的引用變得模糊不清。第十二頁(yè),共八十三頁(yè),編輯于2023年,星期五13二義性問(wèn)題在多繼承時(shí),基類(lèi)之間出現(xiàn)同名成員時(shí),將出現(xiàn)訪(fǎng)問(wèn)時(shí)的二義性(不確定性)。例如,按照下面引用:
voidmain() { SleeperSofass;
ss.SetWeight(20);
//Bed的SetWeight還是Sofa的SetWeight? }第十三頁(yè),共八十三頁(yè),編輯于2023年,星期五14這樣導(dǎo)致了名稱(chēng)沖突(namecollision),在編譯時(shí)將予以拒絕。程序必須在重量前面說(shuō)明基類(lèi):voidmain(){SleeperSofass;
ss.Sofa::SetWeight(20);//說(shuō)明是沙發(fā)重量20斤}
在編寫(xiě)應(yīng)用程序時(shí),程序員還得額外知道類(lèi)的層次信息,加大了復(fù)雜度。這些在單繼承中是不會(huì)出現(xiàn)的。第十四頁(yè),共八十三頁(yè),編輯于2023年,星期五15二義性問(wèn)題舉例classA{public:voidf();};classB{public:voidf();voidg();};classC:publicA,publicB{public:voidg();voidh();};main(){Cc;c.f();c.g();}//error第十五頁(yè),共八十三頁(yè),編輯于2023年,星期五16二義性的解決方法解決方法一:用類(lèi)名來(lái)限定
c1.A::f()或c1.B::f()解決方法二:同名覆蓋
在C中定義一個(gè)同名成員函數(shù)f(),f()再根據(jù)需要調(diào)用A::f()或B::f()第十六頁(yè),共八十三頁(yè),編輯于2023年,星期五17二義性問(wèn)題的說(shuō)明二義性檢查是在訪(fǎng)問(wèn)控制或類(lèi)型檢查之前進(jìn)行的。因此當(dāng)不同基類(lèi)成員中具有相同名字時(shí)就會(huì)出現(xiàn)二義性,即只有一個(gè)名字是可以被派生類(lèi)訪(fǎng)問(wèn)或只有一個(gè)名字的類(lèi)型與要求相符。第十七頁(yè),共八十三頁(yè),編輯于2023年,星期五18本章主要內(nèi)容多繼承如何工作繼承的模糊性(二義性問(wèn)題)虛基類(lèi)多繼承的構(gòu)造順序第十八頁(yè),共八十三頁(yè),編輯于2023年,星期五19為什么要引入虛基類(lèi)?在C++中,一個(gè)類(lèi)不能多次說(shuō)明為派生類(lèi)的直接基類(lèi),但一個(gè)類(lèi)可以不止一次的成為某個(gè)類(lèi)的間接基類(lèi)。第十九頁(yè),共八十三頁(yè),編輯于2023年,星期五20從意義上來(lái)看,一個(gè)SleeperSofa沒(méi)有沙發(fā)和床兩種重量,如此的繼承不是真實(shí)的現(xiàn)實(shí)世界描述。進(jìn)一步分析可得,床和沙發(fā)都是家具的一種,凡家具都有重量,所以通過(guò)分解來(lái)考察其關(guān)系,如圖
第二十頁(yè),共八十三頁(yè),編輯于2023年,星期五21classFurniture{public: Furniture(){}
voidSetWeight(inti){weight=i;} intGetWeight(){returnweight;}protected: intweight;};classBed:publicFurniture{public: Bed(){} voidSleep(){cout<<"Sleeping...\n";}};classSofa:publicFurniture{public: Sofa(){} voidWatchTV(){cout<<"WatchingTV.\n";}};第二十一頁(yè),共八十三頁(yè),編輯于2023年,星期五22classSleeperSofa:publicBed,publicSofa{public: SleeperSofa():Sofa(),Bed(){} voidFoldOut(){cout<<"Foldoutthesofa.\n";}};voidmain(){ SleeperSofass; ss.SetWeight(20);//編譯出錯(cuò)!模糊的SetWeight成員
Furniture*pF; pF=(Furniture*)&ss;//編譯出錯(cuò)!模糊的Furniture* cout<<pF->GetWeight()<<endl;}第二十二頁(yè),共八十三頁(yè),編輯于2023年,星期五23因?yàn)镾lleperSofa不是直接繼承Furniture,而是Bed和Sofa各自繼承Furniture,所以完整的SleeperSofa對(duì)象內(nèi)存布局如圖所示完整SleeperSofa對(duì)象內(nèi)存布局第二十三頁(yè),共八十三頁(yè),編輯于2023年,星期五24這里一個(gè)Sleepersofa包括一個(gè)完整的Bed,隨后還有一個(gè)完整的Sofa,后面還有一個(gè)Sleepersofa特有的東西。SleeperSofa中的每一個(gè)子對(duì)象都有它自己的Furniture部分。因?yàn)槊總€(gè)子對(duì)象繼承Furniture,所以一個(gè)SleeperSofa包含兩個(gè)Furniture對(duì)象,編譯源文件時(shí),不知道SetWeight()屬于哪一個(gè)Furniture成員,指向Furniture的指針也不知道究竟指哪一個(gè)Furniture。這就是為什么源文件編譯通不過(guò)的原因。
SleeperSofa只需一個(gè)Fumiture,所以我們希望它只含一個(gè)Furniture拷貝,同時(shí)又要共享Bed和Sofa的成員函數(shù)與數(shù)據(jù)成員,C++實(shí)現(xiàn)這種繼承結(jié)構(gòu)的方法稱(chēng)為虛擬繼承(virtualinheritance)。第二十四頁(yè),共八十三頁(yè),編輯于2023年,星期五25虛基類(lèi)的概念當(dāng)在多條繼承路徑上有一個(gè)公共的基類(lèi),在這些路徑中的某幾條的交匯處,這個(gè)公共的基類(lèi)就會(huì)產(chǎn)生多個(gè)副本。在大多數(shù)的應(yīng)用場(chǎng)合,需要派生類(lèi)對(duì)象中所含基類(lèi)的副本只有一個(gè),而不是多個(gè)。C++中的虛基類(lèi)機(jī)制可以實(shí)現(xiàn)這種要求。第二十五頁(yè),共八十三頁(yè),編輯于2023年,星期五26定義用virtual修飾說(shuō)明基類(lèi)
例:classx1:
virtualpublicx{//…}classx2:virtualpublicx{//…}注意:在第一級(jí)繼承時(shí)就要將共同基類(lèi)設(shè)計(jì)為虛基類(lèi)。第二十六頁(yè),共八十三頁(yè),編輯于2023年,星期五27虛基類(lèi)舉例classB{public:intb;};classB1:virtualpublicB{private:intb1;};classB2:virtualpublicB{private:intb2;};classC:publicB1,publicB2{private:floatd;};下面的訪(fǎng)問(wèn)是正確的:
Cobj;obj.b;第二十七頁(yè),共八十三頁(yè),編輯于2023年,星期五28虛基類(lèi)的派生類(lèi)對(duì)象存儲(chǔ)結(jié)構(gòu)示意圖:BB1B2Cb1b2dB1類(lèi)子對(duì)象B2類(lèi)子對(duì)象C類(lèi)對(duì)象bB類(lèi)子對(duì)象第二十八頁(yè),共八十三頁(yè),編輯于2023年,星期五29下面是虛擬繼承的代碼:classFurniture{public: Furniture(){} voidSetWeight(inti){weight=i;} intGetWeight(){returnweight;}protected: intweight;};classBed:virtualpublicFurniture{public: Bed(){} voidSleep(){cout<<"Sleeping...\n";}};classSofa:virtualpublicFurniture{public: Sofa(){} voidWatchTV(){cout<<"WatchingTV.\n";}};第二十九頁(yè),共八十三頁(yè),編輯于2023年,星期五30classSleeperSofa:publicBed,publicSofa{public: SleeperSofa():Sofa(),Bed(){} voidFoldOut(){cout<<"Foldoutthesofa.\n";}};voidmain(){ SleeperSofass; ss.SetWeight(20); cout<<ss.GetWeight()<<endl;}運(yùn)行結(jié)果為:
20第三十頁(yè),共八十三頁(yè),編輯于2023年,星期五31
在Bed和Sofa繼承Furniture中加上virtual關(guān)鍵字,這相當(dāng)于說(shuō),“如果還沒(méi)有Furniture類(lèi),則加入一個(gè)Furniture拷貝,否則就用有的那一個(gè)”。此時(shí)一個(gè)Sleepersofa在內(nèi)存中的布局見(jiàn)圖
在虛擬繼承的情況下,應(yīng)用程序main()中引用GetWeight()不再模糊,我們得到了真正的圖17-2所示的繼承關(guān)系。->虛擬繼承的虛擬和虛擬函數(shù)的虛擬沒(méi)有任何關(guān)系。第三十一頁(yè),共八十三頁(yè),編輯于2023年,星期五32虛基類(lèi)及其派生類(lèi)構(gòu)造函數(shù)在整個(gè)繼承結(jié)構(gòu)中,直接或間接繼承虛基類(lèi)的所有派生類(lèi),都必須在構(gòu)造函數(shù)的成員初始化表中給出對(duì)虛基類(lèi)的構(gòu)造函數(shù)的調(diào)用。如果未列出,則表示調(diào)用該虛基類(lèi)的默認(rèn)構(gòu)造函數(shù)。在建立對(duì)象時(shí),只有最新派生類(lèi)的構(gòu)造函數(shù)調(diào)用虛基類(lèi)的構(gòu)造函數(shù),該派生類(lèi)的其它基類(lèi)對(duì)虛基類(lèi)構(gòu)造函數(shù)的調(diào)用被忽略。虛基類(lèi)的構(gòu)造函數(shù)先于非虛基類(lèi)的構(gòu)造函數(shù)執(zhí)行。第三十二頁(yè),共八十三頁(yè),編輯于2023年,星期五33應(yīng)用舉例人員管理系統(tǒng):有三類(lèi)人員:經(jīng)理、技術(shù)人員、推銷(xiāo)人員,還有銷(xiāo)售經(jīng)理。月薪:經(jīng)理:8000元/月;技術(shù)人員:100元/小時(shí);推銷(xiāo)人員:4%提成;銷(xiāo)售經(jīng)理:5000元月+5%提成。輸出每個(gè)人員的月工資信息。第三十三頁(yè),共八十三頁(yè),編輯于2023年,星期五34應(yīng)用舉例類(lèi)設(shè)計(jì)基類(lèi):employee派生類(lèi):technician、manager和salesman多繼承派生類(lèi):salesmanager第三十四頁(yè),共八十三頁(yè),編輯于2023年,星期五35classemployee{protected:
char*name; //姓名
intindividualEmpNo; //個(gè)人編號(hào)
floataccumPay; //月薪總額
staticintemployeeNo; //本公司職員 編號(hào)目前最大值
public:
employee(); //構(gòu)造函數(shù)
~employee(); //析構(gòu)函數(shù)
virtualvoidpay()=0; //計(jì)算月薪函數(shù)
virtualvoiddisplayStatus()=0;//顯示人員信息
};第三十五頁(yè),共八十三頁(yè),編輯于2023年,星期五36
classtechnician:publicemployee//技術(shù)人員類(lèi)
{private:
floathourlyRate; //每小時(shí)酬金
intworkHours; //當(dāng)月工作時(shí)數(shù)
public:
technician(); //構(gòu)造函數(shù)
voidpay(); //計(jì)算月薪函數(shù)
voiddisplayStatus();//顯示人員信息};第三十六頁(yè),共八十三頁(yè),編輯于2023年,星期五37classsalesman:virtualpublicemployee//兼職推銷(xiāo)員類(lèi){protected:
floatCommRate;//按銷(xiāo)售額提取酬金的百分比
floatsales; //當(dāng)月銷(xiāo)售額
public:
salesman(); //構(gòu)造函數(shù)
voidpay(); //計(jì)算月薪函數(shù)
voiddisplayStatus();//顯示人員信息};第三十七頁(yè),共八十三頁(yè),編輯于2023年,星期五38classmanager:virtualpublicemployee//經(jīng)理類(lèi){protected:floatmonthlyPay; //固定月薪數(shù)
public:manager(); //構(gòu)造函數(shù)
voidpay(); //計(jì)算月薪函數(shù)
voiddisplayStatus();//顯示人員信息
};第三十八頁(yè),共八十三頁(yè),編輯于2023年,星期五39classsalesmanager:publicmanager,publicsalesman//銷(xiāo)售經(jīng)理類(lèi)
{public:salesmanager();//構(gòu)造函數(shù)
voidpay();//計(jì)算月薪函數(shù)
voiddisplayStatus();//顯示人員信息
};第三十九頁(yè),共八十三頁(yè),編輯于2023年,星期五40employee::employee(){charnamestr[50]; //輸人雇員姓名時(shí)首先臨時(shí)存放在namestr中
cout<<"請(qǐng)輸入下一個(gè)雇員的姓名:"; cin>>namestr;name=newchar[strlen(namestr)+1]; //動(dòng)態(tài)申請(qǐng)用于存放姓名的內(nèi)存空間
strcpy(name,namestr);//將臨時(shí)存放的姓名復(fù)制到nameindividualEmpNo=employeeNo++;//新輸人的員工,其編號(hào)為目前最大編號(hào)加1 accumPay=0.0;//月薪總額初值為0}第四十頁(yè),共八十三頁(yè),編輯于2023年,星期五41employee::~employee(){deletename; //在析構(gòu)函數(shù)中刪除為存放姓名動(dòng)態(tài)分配的內(nèi)存空間}第四十一頁(yè),共八十三頁(yè),編輯于2023年,星期五42technician::technician(){hourlyRate=100;//每小時(shí)酬金100元}voidtechnician::pay(){cout<<"請(qǐng)輸入"<<name<<"本月的工作時(shí)數(shù):";cin>>workHours;accumPay=hourlyRate*workHours; //計(jì)算月薪,按小時(shí)計(jì)酬
cout<<“兼職技術(shù)人員”<<name<<“編號(hào)“
<<individualEmpNo<<“本月工資”
<<accumPay<<endl;}voidtechnician::displayStatus(){cout<<“兼職技術(shù)人員”<<name<<“編號(hào)”
<<individualEmpNo<<"級(jí)別為"<<grade<<"級(jí),已付本月工資"<<accumPay<<endl;}第四十二頁(yè),共八十三頁(yè),編輯于2023年,星期五43salesman::salesman(){CommRate=0.04;//銷(xiāo)售提成比例4%}voidsalesman::pay(){cout<<"請(qǐng)輸入"<<name<<"本月的銷(xiāo)售額:";cin>>sales;accumPay=sales*CommRate;//月薪=銷(xiāo)售提成
cout<<"推銷(xiāo)員"<<name<<"編號(hào)"<<individualEmpNo<<"本月工資"<<accumPay<<endl;}voidsalesman::displayStatus(){cout<<"推銷(xiāo)員"<<name<<"編號(hào)"<<individualEmpNo<<“級(jí)別為”<<grade<<“級(jí),已付本月工資”
<<accumPay<<endl;}第四十三頁(yè),共八十三頁(yè),編輯于2023年,星期五44manager::manager(){monthlyPay=8000;//固定月薪8000元}voidmanager::pay(){accumPay=monthlyPay;//月薪總額即固定月薪數(shù)
cout<<"經(jīng)理"<<name<<"編號(hào)"<<individualEmpNo<<"本月工資"<<accumPay<<endl;}voidmanager::displayStatus(){cout<<"經(jīng)理"<<name<<"編號(hào)"<<individualEmpNo<<“級(jí)別為”<<grade<<“級(jí),已付本月工資”
<<accumPay<<endl;}第四十四頁(yè),共八十三頁(yè),編輯于2023年,星期五45salesmanager::salesmanager(){monthlyPay=5000;CommRate=0.005;}voidsalesmanager::pay(){cout<<“請(qǐng)輸入”<<employee::name<<“所管轄部門(mén)本月的銷(xiāo)售總額:";cin>>sales;accumPay=monthlyPay+CommRate*sales;//月薪=固定月薪十銷(xiāo)售提成
cout<<"銷(xiāo)售經(jīng)理"<<name<<"編號(hào)"<<individualEmpNo<<"本月工資"<<accumPay<<endl;}voidsalesmanager::displayStatus(){cout<<"銷(xiāo)售經(jīng)理"<<name<<"編號(hào)"<<individualEmpNo<<“級(jí)別為”<<grade<<“級(jí),已付本月工資”
<<accumPay<<endl;}第四十五頁(yè),共八十三頁(yè),編輯于2023年,星期五46intmain(){managerm1;techniciant1;salesmanagersm1;salesmans1;employee*emp[4]={&m1,&t1,&sm1,&s1}; //用指針數(shù)組存放各個(gè)對(duì)象的地址
for(inti=0;i<4;i++){emp[i]->pay(); //顯示月薪
emp[i]->displayStatus(); //顯示人員信息
}return0;}第四十六頁(yè),共八十三頁(yè),編輯于2023年,星期五47本章主要內(nèi)容多繼承如何工作繼承的模糊性(二義性問(wèn)題)虛基類(lèi)多繼承的構(gòu)造順序保護(hù)繼承與私有繼承第四十七頁(yè),共八十三頁(yè),編輯于2023年,星期五48多繼承時(shí)的構(gòu)造函數(shù)派生類(lèi)名::派生類(lèi)名(基類(lèi)1形參,基類(lèi)2形參,…,基類(lèi)n形參,本類(lèi)形參):基類(lèi)名1(參數(shù)),基類(lèi)名2(參數(shù)),…,基類(lèi)名n(參數(shù)){
本類(lèi)成員初始化賦值語(yǔ)句;};第四十八頁(yè),共八十三頁(yè),編輯于2023年,星期五49多繼承時(shí)的構(gòu)造函數(shù)當(dāng)基類(lèi)中定義有默認(rèn)形式的構(gòu)造函數(shù)或未定義構(gòu)造函數(shù)時(shí),派生類(lèi)構(gòu)造函數(shù)的定義中可以省略對(duì)基類(lèi)構(gòu)造函數(shù)的調(diào)用,也可以不定義,全采用默認(rèn)形式構(gòu)造函數(shù)。當(dāng)基類(lèi)定義有帶形參的構(gòu)造函數(shù)時(shí),派生類(lèi)也應(yīng)定義構(gòu)造函數(shù),提供將參數(shù)傳遞給基類(lèi)構(gòu)造函數(shù)的途徑。第四十九頁(yè),共八十三頁(yè),編輯于2023年,星期五50構(gòu)造函數(shù)的調(diào)用次序1.調(diào)用基類(lèi)構(gòu)造函數(shù),調(diào)用順序按照它們被繼承時(shí)聲明的順序(從左向右)。2.調(diào)用成員對(duì)象的構(gòu)造函數(shù),調(diào)用順序按照它們?cè)陬?lèi)中聲明的順序。3.派生類(lèi)的構(gòu)造函數(shù)體中的內(nèi)容。第五十頁(yè),共八十三頁(yè),編輯于2023年,星期五51多繼承且有內(nèi)嵌對(duì)象時(shí)
的構(gòu)造函數(shù)派生類(lèi)名::派生類(lèi)名(基類(lèi)1形參,基類(lèi)2形參,…,基類(lèi)n形參,本類(lèi)形參):基類(lèi)名1(參數(shù)),基類(lèi)名2(參數(shù)),...基類(lèi)名n(參數(shù)),對(duì)象數(shù)據(jù)成員的初始化{
本類(lèi)成員初始化賦值語(yǔ)句;};第五十一頁(yè),共八十三頁(yè),編輯于2023年,星期五52舉例#include<iostream.h>classB1{public:B1(inti){cout<<“ConstructingB1”<<i<<endl;}};classB2{public:B2(intj){cout<<“ConstructingB2”<<j<<endl;}};第五十二頁(yè),共八十三頁(yè),編輯于2023年,星期五classB3{public:B3(){cout<<“ConstructingB3*”<<endl;}};classC:publicB2,publicB1,publicB3//派生類(lèi){public:C(inta,intb,intc,intd): B1(a),memB2(d),memB1(c),B2(b){}private:B1memB1;
B2memB2; B3memB3;};voidmain(){Cobj(1,2,3,4);}第五十三頁(yè),共八十三頁(yè),編輯于2023年,星期五調(diào)用順序:先按派生類(lèi)聲明時(shí)基類(lèi)的順序調(diào)用基類(lèi)的構(gòu)造函數(shù):B2、B1、B3;再按成員對(duì)象定義的順序,調(diào)用成員對(duì)象的構(gòu)造函數(shù):B1、B2、B3程序運(yùn)行結(jié)果:ConstructingB22ConstructingB11ConstructingB3*ConstructingB13ConstructingB24ConstructingB3*第五十四頁(yè),共八十三頁(yè),編輯于2023年,星期五55多重繼承帶有虛擬基類(lèi)的順序構(gòu)造對(duì)象的規(guī)則需要擴(kuò)展以控制多重繼承。構(gòu)造函數(shù)按下列順序被調(diào)用:
(1)任何虛擬基類(lèi)的構(gòu)造函數(shù)按照它們被繼承的順序構(gòu)造;
(2)任何非虛擬基類(lèi)的構(gòu)造函數(shù)按照它們被繼承的順序構(gòu)造;
(3)任何成員對(duì)象的構(gòu)造函數(shù)按照它們聲明的順序調(diào)用;
(4)類(lèi)自己的構(gòu)造函數(shù)。第五十五頁(yè),共八十三頁(yè),編輯于2023年,星期五56classOBJ1{public: OBJ1(){cout<<"OBJ1\n";}};classOBJ2{public: OBJ2(){cout<<"OBJ2\n";}};第五十六頁(yè),共八十三頁(yè),編輯于2023年,星期五57classBase1{public: Base1(){cout<<"Base1\n";}};classBase2{public: Base2(){cout<<"Base2\n";}};classBase3{public: Base3(){cout<<"Base3\n";}};classBase4{public: Base4(){cout<<"Base4\n";}};第五十七頁(yè),共八十三頁(yè),編輯于2023年,星期五58classDerived:publicBase1,virtualpublicBase2,publicBase3,virtualpublicBase4{public: Derived():Base4(),Base3(),Base2(),Base1(),obj2(),obj1() { cout<<"Derivedok.\n"; }protected: OBJ1obj1; OBJ2obj2;};voidmain(){ Derivedaa; cout<<"Thisisok.\n";}第五十八頁(yè),共八十三頁(yè),編輯于2023年,星期五59運(yùn)行結(jié)果為:
Base2 Base4 Base1 Base3 OBJ1 OBJ2 Derivedok. Thisisok.
Derived的虛基類(lèi)Base2和Base4最先構(gòu)造,盡管它在Derived類(lèi)中出現(xiàn)的順序不在最前面;Derived的非虛基類(lèi)其次構(gòu)造,不管它在Derived構(gòu)造函數(shù)中出現(xiàn)的順序如何;Derived的組合對(duì)象obj1和。obj2隨后構(gòu)造,它以類(lèi)定義時(shí),數(shù)據(jù)成員排列順序?yàn)闇?zhǔn),不管在Derived構(gòu)造函數(shù)中出現(xiàn)順序怎樣;最后是Derived類(lèi)構(gòu)造函數(shù)本身。第五十九頁(yè),共八十三頁(yè),編輯于2023年,星期五60>在語(yǔ)言中實(shí)現(xiàn)多繼承并不容易,這主要是編譯程序問(wèn)題,還有模糊性問(wèn)題。建議你如果可能,在進(jìn)一步閱讀有關(guān)參考書(shū)之前,盡量避免用多重繼承。單個(gè)繼承提供了足夠強(qiáng)大的功能,不一定非用多重繼承不可。我們應(yīng)先學(xué)會(huì)閱讀一些商品化的類(lèi)庫(kù)源程序中有關(guān)多重繼承的部分,因?yàn)槟切┒际墙?jīng)過(guò)測(cè)試的安全代碼。第六十頁(yè),共八十三頁(yè),編輯于2023年,星期五61本章主要內(nèi)容多繼承如何工作多繼承的構(gòu)造順序繼承的模糊性(二義性問(wèn)題)虛基類(lèi)繼承的訪(fǎng)問(wèn)控制
保護(hù)繼承與私有繼承
第六十一頁(yè),共八十三頁(yè),編輯于2023年,星期五62
繼承可以公共繼承,也可保護(hù)繼承和私有繼承。對(duì)于不同的繼承方式,其訪(fǎng)問(wèn)控制是不同的第六十二頁(yè),共八十三頁(yè),編輯于2023年,星期五63我們?cè)谇懊嬗懻摰念?lèi)的繼承關(guān)系都是公共繼承的。在公共繼承的類(lèi)中,基類(lèi)的每個(gè)成員在子類(lèi)中保持同樣的訪(fǎng)問(wèn)方式。即在基類(lèi)中為public的成員,子類(lèi)中可以訪(fǎng)問(wèn)之,并據(jù)為public的;基類(lèi)中為protected的成員,子類(lèi)中也可訪(fǎng)問(wèn)之,并據(jù)為protected的;基類(lèi)中為private的成員,在子類(lèi)中不能訪(fǎng)問(wèn)之,這就像在應(yīng)用程序中不能訪(fǎng)問(wèn)類(lèi)中私有成員一樣。下面的例子中的代碼,是對(duì)上表的一個(gè)解釋?zhuān)旱诹?yè),共八十三頁(yè),編輯于2023年,星期五64classBase {public: intm1;protected: intm2;private: intm3; };classPrivateClass:privateBase//私有繼承
{ public: voidtest() { m1=1;//ok:將m1據(jù)為private m2=2;//ok:將m2據(jù)為private m3=3;//不可訪(fǎng)問(wèn)
} };第六十四頁(yè),共八十三頁(yè),編輯于2023年,星期五65classDerivedFromPri:publicPrivateClass { public: voidtest() { m1=1;//不可訪(fǎng)問(wèn)基類(lèi)的私有成員
m2=2;//不可訪(fǎng)問(wèn)
m3=3;///不可訪(fǎng)問(wèn)
} };classProtectedClass:protectedBase//保護(hù)繼承
{ public: voidtest() { m1=1;//ml據(jù)為protected m2=2;//m2據(jù)為protected m3=3;//不可訪(fǎng)問(wèn)
} };第六十五頁(yè),共八十三頁(yè),編輯于2023年,星期五66classDerivedFromPro:publicProtectedClass { public: voidtest() { m1=1;//ml仍為protected m2=2;//m2仍為protected m3=3;//不可訪(fǎng)問(wèn)
} };classPublicClass:publicBase//公共繼承
{ public: voidtest() { m1=1;//ml為public m2=2;//m2為protected m3=3;//不可訪(fǎng)問(wèn)
} };第六十六頁(yè),共八十三頁(yè),編輯于2023年,星期五67classDerivedFromPub:publicPublicClass { public: voidtest() { m1=1;//ml仍保持為public m2=2;//m2仍保持為prOtected m3=3;//不可訪(fǎng)問(wèn)
}
}; 第六十七頁(yè),共八十三頁(yè),編輯于2023年,星期五68 voidmain() {
PrivateClasspriObj; priObj.m1=1;//error priObj.m2=2;//error priObj.m3=3;//error ProtectedClassproObj; proObj.m1=1;//error proObj.m2=2;//error proObj.m3=3;//error PublicClasspubObj; pubObj.m1=1; pubObj.m2=2;//error pubObj.m3=3;//error
}第六十八頁(yè),共八十三頁(yè),編輯于2023年,星期五69類(lèi)Base包括三個(gè)成員m1,m2,m3,分別定義為public,protected,private。Base作為PrivateClass,ProtectedClass,PublicClass三個(gè)類(lèi)的基類(lèi),這三個(gè)類(lèi)分別用私有、保護(hù)和公共繼承派生。于是在這三個(gè)類(lèi)中,數(shù)據(jù)成員的性質(zhì)發(fā)生了變化:私有繼承時(shí),基類(lèi)中不管是公有的,還是保護(hù)的或者為私有的,一律在子類(lèi)中變成私有成員。保護(hù)繼承時(shí),基類(lèi)中公共和保護(hù)的成員在子類(lèi)中變成保護(hù)的,而基類(lèi)中私有的成員在子類(lèi)中變成私有的。公共繼承時(shí),基類(lèi)中為公共、保護(hù)和私有的成員在子類(lèi)中仍保持為公共、保護(hù)和私有的。第六十九頁(yè),共八十三頁(yè),編輯于2023年,星期五70m3是私有的,它只能被Base訪(fǎng)問(wèn),不能被派生類(lèi)和非成員函數(shù)訪(fǎng)問(wèn)。在所有的test()函數(shù)中引用m3時(shí)將報(bào)錯(cuò)。m1和m2對(duì)直接從Base派生的類(lèi)都可以訪(fǎng)問(wèn)。所以由PrivateClass::test(),ProtectedClass::test()和PublicClass::test()引用這兩個(gè)成員是允許的。
PrivateClass類(lèi)私有繼承Base,這意味著m1和m2對(duì)PrivateClass中的成員現(xiàn)在可以私有訪(fǎng)問(wèn)。因而不能被像DerivedFromPri一樣由PrivateClass直接派生的類(lèi)訪(fǎng)問(wèn)。
ProtectedClass類(lèi)被保護(hù)地繼承Base,這使得m1和m2都被保護(hù)。對(duì)ProtectedClass::test()和DerivedFromPro::test()這兩個(gè)成員都是可訪(fǎng)問(wèn)的。第七十頁(yè),共八十三頁(yè),編輯于2023年,星期五71PublicClass類(lèi)公共繼承Base。在PublicClass中三個(gè)成員都保持它們?cè)贐ase中的訪(fǎng)問(wèn)特性。如果不標(biāo)明繼承為公共還是保護(hù)或者私有,則默認(rèn)的繼承是私有。但最好不要依賴(lài)默認(rèn),如果把繼承類(lèi)型表示清楚,則程序的可讀性會(huì)更好。在單個(gè)類(lèi)中,protected和private沒(méi)有什么區(qū)別。但在繼承關(guān)系中,基類(lèi)的private成員不但對(duì)應(yīng)用程序隱藏,甚至對(duì)派生類(lèi)也隱藏。而基類(lèi)的保護(hù)成員則只對(duì)應(yīng)用程序隱藏,而對(duì)派生類(lèi)則毫不隱瞞。第七十一頁(yè),共八十三頁(yè),編輯于2023年,星期五72本章主要內(nèi)容多繼承如何工作多繼承的構(gòu)造順序繼承的模糊性(二義性問(wèn)題)虛基類(lèi)繼承的訪(fǎng)問(wèn)控制
保護(hù)繼承與私有繼承
第七十二頁(yè),共八十三頁(yè),編輯于2023年,星期五73
一個(gè)私有的或保護(hù)的派生類(lèi)不是子類(lèi),因?yàn)榉枪驳呐缮?lèi)不能做基類(lèi)能做的所有的事。例如,下面的代碼定義了一個(gè)私有繼承基類(lèi)的類(lèi)第七十三頁(yè),共八十三頁(yè),編輯于2023年,星期五74classAnimal { public:
Animal(){}voideat(){cout<<"eat\n";} };
classGiraffe:privateAnimal { public;
Giraffe(){} voidStrechNeck(double){cout<<"strechneck\n";} } classCat:publicAnimal { Ca
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 淺談EPC總承包模式下的造價(jià)管理與控制
- 2025年度住宅小區(qū)綠化工程承包合同范本-@-1
- 2025年新能源車(chē)輛配送及維護(hù)保養(yǎng)服務(wù)合同
- 勞務(wù)合同范本內(nèi)容
- 個(gè)人信譽(yù)合同范例
- 借款合同范例匯編
- 勞動(dòng)終止合同范例
- 上海個(gè)人租賃合同范本
- 個(gè)人吊車(chē)轉(zhuǎn)讓合同范本
- 企業(yè)藥品采購(gòu)合同范例
- NB-T 10609-2021 水電工程攔漂排設(shè)計(jì)規(guī)范
- 藝術(shù)課程標(biāo)準(zhǔn)(2022年版)
- 衛(wèi)生部手術(shù)分級(jí)目錄(2023年1月份修訂)
- 即興口語(yǔ)(姜燕)-課件-即興口語(yǔ)第一章PPT-中國(guó)傳媒大學(xué)
- 文物保護(hù)項(xiàng)目可行性研究報(bào)告
- 冷卻塔是利用水和空氣的接觸
- 我國(guó)古代職業(yè)教育的發(fā)展
- 企業(yè)注銷(xiāo)鑒證工作底稿
- 環(huán)境因素多因子評(píng)價(jià)方法
- 冷卻水路設(shè)計(jì)原則與優(yōu)化實(shí)例
- 門(mén)窗類(lèi)英語(yǔ)匯總
評(píng)論
0/150
提交評(píng)論