版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第8章繼承與派生8.1派生類的定義及其構(gòu)造和析構(gòu)函數(shù)8.2派生類使用例--公司雇員檔案的管理8.3多態(tài)性與虛函數(shù)8.4虛函數(shù)使用例1--計(jì)算函數(shù)的定積分8.5與基類對(duì)象和派生類對(duì)象相關(guān)的賦值兼容性問(wèn)題8.6虛函數(shù)使用例2--利用圖元類畫(huà)圖8.7派生關(guān)系中的二義性處理8.8虛基類
1C++程序用不同的類定義來(lái)表示一組數(shù)據(jù)以及對(duì)這些數(shù)據(jù)的操作與處理,而類之間往往具有某種關(guān)系,“繼承與派生”就是類間的一種常用關(guān)系。
例如,交通工具→汽車→轎車→紅旗轎車。
具有層次關(guān)系!汽車 是一種特殊的交通工具轎車 是一種特殊的汽車紅旗轎車是一種特殊的轎車2
只要定義清楚了“交通工具”,那么在定義“汽車”時(shí)(注意,它就是交通工具),只需再說(shuō)明它的特殊性(而不必重新從頭定義?。?。同理,只要定義清楚了“轎車”,那么在定義“紅旗轎車”時(shí)(注意,它就是轎車),只需再說(shuō)明它的特殊性(根本不必重新從頭定義?。?。
又例如,公司四種雇員檔案的管理:
employee(雇員):姓名、年齡、工資;
manager(經(jīng)理):姓名、年齡、工資、行政級(jí)別;
engineer(工程師):姓名、年齡、工資、專業(yè)、學(xué)位;
director(高級(jí)主管):姓名、年齡、工資、專業(yè)、學(xué)位、職務(wù)。3
C++提供了類定義的派生和繼承功能,能很好地解決上述問(wèn)題(使代碼可重用,避免重復(fù)?。?。
若類A是類B的基類(父類),則類B是類A的派生類(子類)。也可以說(shuō),類B(子類)繼承了類A(父類);或說(shuō),類A(父類)派生出類B(子類)。4 8.1派生類的定義及其構(gòu)造和析構(gòu)函數(shù)
--參看書(shū)p193-197,8.2.1與8.2.2小節(jié)1.派生類的定義
class<派生類類型名>:<基類表>{
private: <各私有成員說(shuō)明>;
public: <各公有成員說(shuō)明>;
protected: <各保護(hù)成員說(shuō)明>; <以關(guān)鍵字friend開(kāi)頭的友元說(shuō)明>;};
5
<基類表>的一般格式為:
<派生方式><基類名1>,...,<派生方式><基類名n>
而<派生方式>又可為private、public或protected。6
派生方式(基類 在基類中的在派生類中的被繼承方式)存取權(quán)限 的存取權(quán)限==================================================
public public public public potected protected public private (inaccessible)
potected public potected potected potected protected
potected private (inaccessible) private public private private potected private private private (inaccessible)
==================================================7
注意:
public派生方式:使基類的公有成員和保護(hù)成員在派生類中仍然是公有成員和保護(hù)成員,而基類的私有成員不可在派生類中被存取。
protected派生方式:使基類的公有成員和保護(hù)成員在派生類中都變?yōu)楸Wo(hù)成員,而基類的私有成員不可在派生類中被存取。
private派生方式:使基類的公有成員和保護(hù)成員在派生類中都變?yōu)樗接谐蓡T,而基類的私有成員不可在派生類中被存取。
8派生類中可出現(xiàn)四種成員:
1)不可訪問(wèn)的成員--基類的private私有成員被繼承過(guò)來(lái)后,這些成員在派生類中是不可訪問(wèn)的。
2)私有成員--包括在派生類中新增加的private私有成員以及從基類私有繼承過(guò)來(lái)的某些成員。這些成員在派生類中是可以訪問(wèn)的。
3)保護(hù)成員--包括在派生類中新增加的potected保護(hù)成員以及從基類繼承過(guò)來(lái)的某些成員。這些成員在派生類中是可以訪問(wèn)的。
4)公有成員--包括在派生類中新增加的public公有成員以及從基類公有繼承過(guò)來(lái)的基類的public成員。這些成員不僅在派生類中可以訪問(wèn),而且在建立派生類對(duì)象的模塊中,也可以通過(guò)對(duì)象來(lái)訪問(wèn)它們。9
分析下述程序中的繼承與派生關(guān)系,并上機(jī)進(jìn)行測(cè)試驗(yàn)證,以加深對(duì)它們進(jìn)行正確使用的理解。classbaseCla{
intprivData;protected:
intprotData;public:
intpublData;};10classpublDrvCla:publicbaseCla{public: voidusebaseClaData(){
publData=11;//OK!
protData=12; //OK!
privData=13; //ERROR! }};11
classclaD21:publicpublDrvCla{ public: voidusebaseClaData(){
publData=111; //OK!
protData=121; //OK!
privData=131; //ERROR! }};12
classprotDrvCla:protectedbaseCla{ public: voidusebaseClaData(){
publData=21;//OK!
protData=22; //OK!
privData=23; //ERROR! }};13classclaD22:publicprotDrvCla{ public: voidusebaseClaData(){
publData=211; //OK!
protData=221; //OK!
privData=231; //ERROR! }};14
classprivDrvCla:privatebaseCla{public: voidusebaseClaData(){
publData=31; //OK!
protData=32; //OK!
privData=33; //ERROR! }};15classclaD23:publicprivDrvCla{public: voidusebaseClaData(){
publData=311; //ERROR!
protData=321; //ERROR!
privData=331; //ERROR! }};16voidmain(){
baseClaob0; ob0.publData=1; //OK! tData=2; //ERROR! ob0.privData=3; //ERROR! claD21d21; claD22d22; claD23d23; d21.publData=4; //OK! tData=5; //ERROR! d21.privData=6; //ERROR! d22.publData=7; //ERROR! tData=8; //ERROR! d22.privData=9; //ERROR! d23.publData=7; //ERROR! tData=8; //ERROR! d23.privData=9; //ERROR!}17
2.派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)
派生類的構(gòu)造函數(shù)的一般格式如下:
<派生類名>(<參數(shù)總表>):<初始化符表> { <構(gòu)造函數(shù)體> }
而<初始化符表>按如下格式構(gòu)成:<基類名1>(<基類參數(shù)表1>),...,<基類名n>(<基類參數(shù)表n>),<對(duì)象成員名1>(<對(duì)象成員參數(shù)表1>),...,<對(duì)象成員名m>(<對(duì)象成員參數(shù)表m>)
(注:若無(wú)對(duì)象成員時(shí),則不出現(xiàn)此后半部分;基類名與對(duì)象成員名的次序無(wú)關(guān)緊要,各自出現(xiàn)的順序可以任意)
18派生類構(gòu)造函數(shù)執(zhí)行的一般次序如下:(1)調(diào)用各基類的構(gòu)造函數(shù),調(diào)用順序繼承時(shí)的聲明順序。(2)若派生類含有對(duì)象成員的話,調(diào)用各對(duì)象成員的構(gòu)造函數(shù),調(diào)用順序按照聲明順序。(3)執(zhí)行派生類構(gòu)造函數(shù)的函數(shù)體。析構(gòu)派生類對(duì)象時(shí),其執(zhí)行次序恰與構(gòu)造時(shí)的次序相反。19
//改造書(shū)P195-197之示例#include<iostream.h>
classCB{
intb;public: CB(intn){b=n;cout<<"CB::b="<<b<<endl;}; ~CB(){cout<<"CBobjisdestrcting"<<endl;};};
classCC{
intc;public: CC(intn1,intn2){c=n1;cout<<"CC::c="<<c<<endl;}; ~CC(){cout<<"CCobjisdestructing"<<endl;};};20classCD:publicCB,publicCC{
intd;public: CD(intn1,intn2,intn3,intn4) :CC(n3,n4),CB(n2){ d=n1; cout<<"CD::d="<<d<<endl; };
~CD(){cout<<"CDobjisdestructing"<<endl;};};voidmain(void){CDCDobj(2,4,6,8);}
21運(yùn)行結(jié)果為:CB::b=4CC::c=6CD::d=2CDobjisdestructingCCobjisdestructingCBobjisdestrcting
思考:將派生類CD改寫(xiě)為如下形式后,請(qǐng)給出輸出結(jié)果。22classCD:publicCB,publicCC{
intd; CCobcc; CBobcb;public: CD(intn1,intn2,intn3,intn4) :CC(n3,n4),CB(n2),obcb(100+n2),obcc(100+n3,100+n4){ d=n1; cout<<"CD::d="<<d<<endl; }; ~CD(){cout<<"CDobjisdestructing"<<endl;};};23
輸出:CB::b=4CC::c=6CC::c=106CB::b=104CD::d=2CDobjisdestructingCBobjisdestrcting.CCobjisdestructingCCobjisdestructingCBobjisdestrcting248.2派生類使用例--公司雇員檔案的管理
--參看書(shū)p190-193,8.1節(jié)
假設(shè)公司雇員分為:雇員(employee)、經(jīng)理(manager)、工程師(engineer)、高級(jí)主管(director)。而且假定只關(guān)心這幾類雇員各自的如下一些數(shù)據(jù):
employee(雇員)類:姓名、年齡、工資;
manager(經(jīng)理)類:姓名、年齡、工資、行政級(jí)別;
engineer(工程師)類:姓名、年齡、工資、專業(yè)、學(xué)位;
director(高級(jí)主管)類:姓名、年齡、工資、專業(yè)、學(xué)位、職務(wù)。25
(具體程序見(jiàn)書(shū)p190--193)
#include<iostream.h>#include<string.h>classemployee{//employee類(類型),將作為其它幾個(gè)類的基類
shortage; floatsalary;protected: char*name;26
public: employee(shortag,floatsa,char*na){ age=ag; salary=sa; name=newchar[strlen(na)+1];
strcpy(name,na); }
voidprint()const{
cout<<""<<name<<":";
cout<<age<<":";
cout<<salary<<endl; }
~employee(){delete[]name;}};
27classmanager:publicemployee{ //派生類
intlevel;public: manager(shortag,floatsa,char*na,intlev) :employee(ag,sa,na){ //對(duì)基類初始化負(fù)責(zé)
level=lev; }
voidprint()const{ employee::print();//調(diào)用基類print顯示“共性”數(shù)據(jù)
cout<<"level:"<<level<<endl; } };28
/*注意:允許派生類中的print與基類的print重名,按如下規(guī)定進(jìn)行處理:對(duì)子類而言,不加類名限定時(shí)默認(rèn)為是處理子類成員,而要訪問(wèn)父類重名成員時(shí),則要通過(guò)類名限定*/classengineer:publicemployee{ charspeciality,adegree;public: ...};enumptitle{PS,GM,VPS,VGM};classdirector:publicmanager{
ptitlepost;public: ...};29voidmain(){ //主函數(shù)
employeeemp1(23,610.5,"zhang"),emp2(27,824.75,"zhao"); managerman1(32,812.45,"li",11),man2(34,1200.5,"cui",7); engineereng(26,1420.10,"meng",'E','M'); directordir(38,1800.2,"zhou",2,GM); emp1.print(); emp2.print(); man1.print(); man2.employee::print(); //調(diào)用基類的print eng.print(); dir.print();}30程序執(zhí)行后的顯示結(jié)果如下:
zhang:23:610.5
zhao:27:824.75
li:32:812.45level:11cui:34:1200.5
meng:26:1420.1
speciality:Eacademicdegree:M
zhou:38:1800.2level:2 post:1318.3多態(tài)性與虛函數(shù)
--參看書(shū)p200,8.3節(jié)
1.函數(shù)重載(overloading)與靜態(tài)聯(lián)編(staticbinding)
函數(shù)重載(overloading)指的是,允許多個(gè)不同函數(shù)使用同一個(gè)函數(shù)名,但要求這些同名函數(shù)具有不同的參數(shù)表。.參數(shù)表中的參數(shù)個(gè)數(shù)不同;.參數(shù)表中對(duì)應(yīng)的參數(shù)類型不同;.參數(shù)表中不同類型參數(shù)的次序不同。32
例:
int
abs(intn){ return(n<0?-n:n); }
floatabs(floatn) { if(f<0)f=-f; returnf; }
系統(tǒng)對(duì)函數(shù)重載這種多態(tài)性的分辨與處理,是在編譯階段完成的--靜態(tài)聯(lián)編(staticbinding)。33
2.函數(shù)超載(overriding)、虛函數(shù)(virtualfunction)及動(dòng)態(tài)聯(lián)編(dynamicbinding)
(1)函數(shù)超載(overriding)
.僅在基類與其派生類的范圍內(nèi)實(shí)現(xiàn);.允許多個(gè)不同函數(shù)使用完全相同的函數(shù)名、函數(shù)參數(shù)表以及函數(shù)返回類型;
34
(2)虛函數(shù)(virtualfunction)
.在定義某一基類(或其派生類)時(shí),若將其中的某一函數(shù)成員的屬性說(shuō)明為virtual,則稱該函數(shù)為虛函數(shù)(virtualfunction)。.虛函數(shù)的使用與函數(shù)超載密切相關(guān)。若基類中某函數(shù)被說(shuō)明為虛函數(shù),則意味著其派生類中也要用到與該函數(shù)同名、同參數(shù)表、同返回類型、但函數(shù)(實(shí)現(xiàn))體不同的這同一個(gè)所謂的超載函數(shù)。35
classgraphelem{protected:
intcolor;public:
graphelem(intcol){ color=col; } virtualvoiddraw(){...};//虛函數(shù)draw,每一個(gè)類都要“draw”出屬于它的類對(duì)象圖形};
36classline:publicgraphelem{public: virtualvoiddraw(){...};//虛函數(shù)draw,負(fù)責(zé)畫(huà)出“l(fā)ine” ...};
classcircle:publicgraphelem{public: virtualvoiddraw(){...};//虛函數(shù)draw,負(fù)責(zé)畫(huà)出“circle” ...};
37classtriangle:publicgraphelem{public: virtualvoiddraw(){...};//虛函數(shù)draw,負(fù)責(zé)畫(huà)出“triangle” ...};
(3)動(dòng)態(tài)聯(lián)編(dynamicbinding)
與虛函數(shù)以及程序中使用指向基類的指針(變量)密切相關(guān)。注意:C++規(guī)定,基類指針可以指向其派生類的對(duì)象(也即,可將派生類對(duì)象的地址賦給其基類指針變量),但反過(guò)來(lái)不可以。這一點(diǎn)正是函數(shù)超載及虛函數(shù)用法的基礎(chǔ)。38
例1.建立上述類line、類circle以及類triangle的類對(duì)象,而后調(diào)用它們各自的draw函數(shù)“畫(huà)出”它們。
方法1:直接通過(guò)類對(duì)象(由類對(duì)象可以唯一確定要調(diào)用哪一個(gè)類的draw函數(shù))
lineln1; circlecir1; triangletri1;ln1.draw(); cir1.draw(); tri1.draw();39
方法2:使用指向基類的指針(動(dòng)態(tài)聯(lián)編,要靠執(zhí)行程序時(shí)其基類指針的“動(dòng)態(tài)”取值來(lái)確定調(diào)用哪一個(gè)類的draw函數(shù))
graphelem*pObj;lineln1; circlecir1; triangletri1;
pObj=&lin1; pObj->draw();
pObj=&cir1; pObj->draw();
pObj=&tri1; pObj->draw();
40
例2.假設(shè)inte_algo為基類,其中說(shuō)明了一個(gè)虛函數(shù)integrate,并在其三個(gè)派生類中,也說(shuō)明了該虛函數(shù)integrate(使用不同方法計(jì)算定積分)。
那么,可使用函數(shù)integrateFunc來(lái)實(shí)現(xiàn)調(diào)用不同虛函數(shù)integrate的目的:
voidintegrateFunc(inte_algo*p){
//基類指針p可指向任一派生類的對(duì)象
p->integrate();
//調(diào)用的將是不同派生類的integrate函數(shù)}
主調(diào)函數(shù)處使用:integrateFunc(<某派生類的類對(duì)象地址>);41
在編譯階段,系統(tǒng)無(wú)法確定究竟要調(diào)用哪一個(gè)派生類的integrate。此種情況下,將采用動(dòng)態(tài)聯(lián)編方式來(lái)處理:在運(yùn)行階段,通過(guò)p指針的當(dāng)前值,去動(dòng)態(tài)地確定對(duì)象所屬類,而后找到對(duì)應(yīng)虛函數(shù)。
3.純虛函數(shù)與抽象基類
如果不準(zhǔn)備在基類的虛函數(shù)中做任何事情,則可使用如下的格式將該虛函數(shù)說(shuō)明成純虛函數(shù):
virtual<函數(shù)原型>=0;42
純虛函數(shù)不能被直接調(diào)用,它只為其派生類的各虛函數(shù)規(guī)定了一個(gè)一致的“原型規(guī)格”(該虛函數(shù)的實(shí)現(xiàn)將在它的派生類中給出)。
含有純虛函數(shù)的基類稱為抽象基類。注意,不可使用抽象基類來(lái)說(shuō)明并創(chuàng)建它自己的對(duì)象,只有在創(chuàng)建其派生類對(duì)象時(shí),才有抽象基類自身的實(shí)例伴隨而生。
實(shí)際上,抽象基類是其各派生類之共同點(diǎn)的一個(gè)抽象綜合,通過(guò)它,再“加上”各派生類的特有成員以及對(duì)基類中那一純虛函數(shù)的具體實(shí)現(xiàn),方可構(gòu)成一個(gè)具體的實(shí)用類型。
另外:如果一個(gè)抽象基類的派生類中沒(méi)有定義基類中的那一純虛函數(shù)、而只是繼承了基類之純虛函數(shù)的話,則這個(gè)派生類還是一個(gè)抽象基類(其中仍包含著繼承而來(lái)的那一個(gè)純虛函數(shù))。43
8.4虛函數(shù)使用例1--計(jì)算函數(shù)的定積分
--參看書(shū)p205-208,8.4.1小節(jié)
采用矩形法、梯形法以及simpson法來(lái)計(jì)算同一函數(shù)的定積分。
此三種方法均將區(qū)間[a,b]分為n等份,而后以不同方式求出各小段對(duì)應(yīng)的小面積s[i],并將它們相加到一起來(lái)作為近似結(jié)果。
#include<iostream.h>
floatfunction(floatx){//欲積分的函數(shù)
return4.0/(1+x*x);}44
classinte_algo{protected: floata,b; //a,b為積分區(qū)間的左右邊界
intn; //n表示把[a,b]劃分成多少個(gè)小區(qū)段進(jìn)行積分
floath,sum;//h表示步長(zhǎng),sum表示積分結(jié)果值
public:
inte_algo(floatleft,floatright,intsteps){ ... }virtualvoidintegrate(void);//虛函數(shù)integrate};45
classrectangle:publicinte_algo{public: rectangle(floatleft,floatright,intsteps) :inte_algo(left,right,steps){ } virtualvoidintegrate(void); //派生類中說(shuō)明同一個(gè)虛函數(shù)integrate};46
classladder:publicinte_algo{ ...};
classsimpson:publicinte_algo{ ...};
voidinte_algo::integrate(){ ...}47
voidrectangle::integrate(){ /*
派生類rectangle之虛函數(shù)integrate的類外定義,采用矩形法來(lái)計(jì)算函數(shù)的定積分。計(jì)算公式為:
sum=(f(a)+f(a+h)+f(a+2h)+...+f(a+(n-1)h))h */
floatal=a; /*al為調(diào)用f函數(shù)時(shí)的實(shí)參值,依次取值a,a+h,a+2h,...,a+(n-1)h。 */48for(inti=0;i<n;i++)//共在n個(gè)點(diǎn)處計(jì)算函數(shù)值{
sum+=function(al); al+=h; //al每次增加一個(gè)步長(zhǎng)h }; sum*=h;
cout<<sum<<endl; //顯示積分結(jié)果sum}49
voidladder::integrate(){ //梯形法 ...}
voidsimpson::integrate(){ //simpson法 ...}
voidintegrateFunc(inte_algo*p){ p->integrate();}
50voidmain(){ rectanglerec(0.0,1.0,10); ladderlad(0.0,1.0,10);
simpsonsim(0.0,1.0,10);
inte_algo*p;
cout<<"inputanum(1--rectanglemethod,2--laddermethod,3--simpsonmethod)";
intii;
cin>>ii; switch(ii){ case1: //矩形法 {
cout<<"rectanglemethod:suum==>";
integrateFunc(&rec); break; }51case2: //梯形法 {
cout<<"laddermethod:suum==>";
integrateFunc(&lad); break; } case3: //simpson法 {
cout<<"simpsonmethod:suum==>";
integrateFunc(&sim); break; } }}
程序執(zhí)行后的顯示結(jié)果如下:inputanum(1--rectanglemethod,2--laddermethod,3--simpsonmethod)3simpsonmethod:suum==>3.1415952
注:也可將上述的integrateFunc函數(shù)以及main用如下樣式的一個(gè)main函數(shù)來(lái)替代。voidmain(){ rectanglerec(0.0,1.0,10); …
cin>>ii; switch(ii){ case1:{//矩形法
cout<<"rectanglemethod:suum==>"; p=&rec; break; } case2:{//梯形法 ... }
case3:{//simpson法 ... } }
p->integrate();}
53
當(dāng)然,若只為實(shí)現(xiàn)上述功能(任務(wù)),完全可以不用指針,而直接通過(guò)類對(duì)象來(lái)進(jìn)行調(diào)用(此時(shí)將不再通過(guò)動(dòng)態(tài)聯(lián)編)。如,也可使用如下形式的main。
voidmain(){ rectanglerec(0.0,1.0,10); …
cin>>ii; switch(ii){ case1:{ //矩形法
cout<<"rectanglemethod:suum==>"; egrate(); break; } case2:{ //梯形法 ... }
case3:{ //simpson法 ... } }}54
8.5與基類對(duì)象和派生類對(duì)象相關(guān)的賦值兼容性問(wèn)題
1.基類對(duì)象=派生類對(duì)象; //OK!
派生類對(duì)象=基類對(duì)象; //ERROR!
2.指向基類型的指針=派生類對(duì)象的地址;//OK!
指向派生類類型的指針=基類對(duì)象的地址; //ERROR!
注:訪問(wèn)非基類成員部分時(shí),要經(jīng)過(guò)指針類型的強(qiáng)制轉(zhuǎn)換。
3.基類的引用=派生類對(duì)象; //OK!
派生類的引用=基類對(duì)象; //ERROR!
注:通過(guò)引用只可以訪問(wèn)基類成員部分。55
#include<iostream.h>classbase{ //定義基類
inta;public: base(){...} base(intsa){...}
intgeta(){returna;}};
classderived:publicbase{ //派生類
intb;public: derived(){...} derived(intsa,intsb):base(sa){...}
intgetb(){returnb;}};
56
voidmain(){ basebs1(11); derivedder(2,4); bs1=der; //OK! //der=bs1; //ERR! derivedder2(6,8); base*pb=&der2; //OK!
cout<<pb->geta()<<endl; //OK! //cout<<pb->getb()<<endl; //ERR!--訪問(wèn)非基類成員部分
cout<<((derived*)pb)->getb()<<endl; //OK!--經(jīng)過(guò)類型轉(zhuǎn)換 //derived*pd=&bs1; //ERR!}57
8.6虛函數(shù)使用例2--利用圖元類畫(huà)圖
--參看書(shū)p208-212,8.4.2小節(jié)本程序自定義pixel、graphelem、line、rectangle、triangle、circle、square、figure等8個(gè)類(類型)并對(duì)它們進(jìn)行使用。
實(shí)現(xiàn)要點(diǎn):
1.設(shè)立并處理以下圖元:直線(line類),矩形(rectangle類),三角形(triangle類),圓(circle類),正方形(square類)。2.將每一種圖元設(shè)計(jì)成一個(gè)類,在每一個(gè)類的定義中,除含有其構(gòu)造函數(shù)外,還包含一個(gè)可將本類的圖元畫(huà)出來(lái)的公有函數(shù)draw。
58
3.由于每一個(gè)圖元都要用到顏色(color)數(shù)據(jù)成員,所以設(shè)立一個(gè)基類graphelem,它含有protected型數(shù)據(jù)成員color,以及一個(gè)虛函數(shù)draw。
4.
由于不準(zhǔn)備在基類graphelem的虛函數(shù)draw中做任何事情,所以在其原型后加上“=0”字樣而構(gòu)成純虛函數(shù)。從而使graphelem成為抽象基類。
5.程序中至少要設(shè)立具有以下關(guān)系的六個(gè)類:抽象基類graphelem;由graphelem直接派生出的四個(gè)類:line,rectangle,triangle,circle;由rectangle派生出一個(gè)類:square。
6.由于“畫(huà)”以上圖元時(shí),都要用到“點(diǎn)”的概念與位置,所以設(shè)立的第七個(gè)類為:pixel。59
7.
為了通過(guò)虛函數(shù)進(jìn)行動(dòng)態(tài)聯(lián)編處理,需說(shuō)明并使用指向基類graphelem的指針(注,該程序中說(shuō)明了10個(gè)這種指針,放在一個(gè)稱為pg的數(shù)組中,既是說(shuō),pg[0],pg[1],...,pg[9]均為這種指向基類graphelem的指針)。而后通過(guò)這些指針的動(dòng)態(tài)取值(使它們指向不同的派生類),進(jìn)而利用函數(shù)調(diào)用“pg[i]->draw()”(i=0,1,...,9)來(lái)“畫(huà)”出組成一個(gè)圖形的不同圖元來(lái)。本程序中的第八個(gè)類figure(中的paint成員函數(shù))正是用來(lái)完成上述“畫(huà)”圖元功能的。
雖然pixel,figure這兩個(gè)類與其它六個(gè)類沒(méi)有繼承和派生的關(guān)系,但卻有成員關(guān)系。類pixel的對(duì)象要作為graphelem及其派生類的成員和構(gòu)造函數(shù)成員的參數(shù)。而類figure則以graphelem類的對(duì)象指針數(shù)組作為其數(shù)據(jù)成員。60
#include<iostream.h>classpixel{ //類pixel,表示屏幕像素點(diǎn)
intx,y;public: pixel(){ //構(gòu)造函數(shù)一,無(wú)參
x=0; y=0; } pixel(inta,intb){ //構(gòu)造函數(shù)二,參數(shù)a、b表示點(diǎn)的位置
x=a; y=b; } pixel(constpixel&p){ //構(gòu)造函數(shù)三,參數(shù)p為某個(gè)已存在對(duì)象
x=p.x; y=p.y; }
intgetx(){returnx;} //獲取對(duì)象的x值
intgety(){returny;} //獲取對(duì)象的y值};
61
enumcolort{ //枚舉類型,用于定義顏色常量(名字)
black,blue,green,cyan,red,magenta,brown,
lightgray,darkgray,lightblue,lightgreen,
lightcyan,lightred,lightmagenta,yellow,white,blink};
classgraphelem{ //基類graphelem(實(shí)際為抽象基類)protected:colortcolor; //顏色colorpublic:graphelem(colortcol){ color=col; } virtualvoiddraw()=0; //純虛函數(shù)draw
};62
classline:publicgraphelem{ //派生類line pixelstart,end; //成員為pixel類對(duì)象
public: line(pixelsta,pixelen,colortcol) :graphelem(col),start(sta),end(en) {}; virtualvoiddraw(); //虛函數(shù)draw};
63
classrectangle:publicgraphelem{ //派生類rectangle pixelulcorner,lrcorner;public: rectangle(pixelul,pixelel,colortcol) :graphelem(col),ulcorner(ul),lrcorner(el) {}; virtualvoiddraw(); //虛函數(shù)draw};
classcircle:publicgraphelem{ //派生類circle pixelcenter;
intradius;public: circle(pixelcen,intrad,colortcol):graphelem(col),center(cen){ radius=rad; }; virtualvoiddraw(); //虛函數(shù)draw};
64
classtriangle:publicgraphelem{ //派生類triangle pixelpointa,pointb,pointc;public: triangle(pixelpa,pixelpb,pixelpc,colortcol) :graphelem(col),pointa(pa),pointb(pb),pointc(pc) {}; virtualvoiddraw(); //虛函數(shù)draw};
classsquare:publicrectangle{ //派生類squarepublic: square(pixelul,intlh,colortcol) :rectangle(ul,pixel(ul.getx()+lh,ul.gety()+lh),col) {}; virtualvoiddraw(); //虛函數(shù)draw};
65
classfigure{//通過(guò)它的paint函數(shù)可“畫(huà)”出組成一個(gè)圖形的各圖元
graphelem*pg[10]; //pg數(shù)組含有10個(gè)指向基類的指針
public: figure( graphelem*pg1=0,graphelem*pg2=0,
graphelem*pg3=0,graphelem*pg4=0,
graphelem*pg5=0,graphelem*pg6=0,
graphelem*pg7=0,graphelem*pg8=0,
graphelem*pg9=0,graphelem*pg10=0) { //具有參數(shù)默認(rèn)值的構(gòu)造函數(shù)
pg[0]=pg1; pg[1]=pg2; pg[2]=pg3; pg[3]=pg4; pg[4]=pg5; pg[5]=pg6; pg[6]=pg7; pg[7]=pg8; pg[8]=pg9; pg[9]=pg10; } voidpaint(){ //“畫(huà)”出圖形的各圖元
for(inti=0;i<10;i++) if(pg[i]!=0) pg[i]->draw(); };};
66
voidmain(){ //說(shuō)明9個(gè)類對(duì)象(圖元),它們是構(gòu)成一個(gè)圖形的九個(gè)“部件”
squaresq(pixel(40,40),120,black); //正方
circlece1(pixel(100,100),50,green); //圓
circlece2(pixel(100,100),2,blue); triangletr1(pixel(100,62),pixel(98,97),pixel(102,97),blue);//三角triangletr2(pixel(98,103),pixel(102,103),pixel(100,130),blue); rectanglere1(pixel(98,54),pixel(102,62),red); //長(zhǎng)方
rectanglere2(pixel(98,138),pixel(102,146),red); rectanglere3(pixel(54,98),pixel(62,102),red); rectanglere4(pixel(138,98),pixel(146,102),red);
figurefig(&sq,&ce1,&ce2,&re1,&re2,&re3,&re4,&tr1,&tr2);//圖形
fig.paint(); //調(diào)用paint函數(shù),“畫(huà)”出fig對(duì)象的9個(gè)圖元}67
程序說(shuō)明:(1)figure類的構(gòu)造函數(shù),含有10個(gè)參數(shù),且該10個(gè)參數(shù)均為可缺省參數(shù)(被賦了缺省值的參數(shù),調(diào)用時(shí),相應(yīng)實(shí)參可缺省)。說(shuō)明figure類對(duì)象時(shí),其實(shí)參可為10個(gè)(或少于10個(gè))指向graphelem不同派生類對(duì)象的具體指針(注意,C++允許基類指針指向其派生類對(duì)象;而此處的各派生類對(duì)象正是準(zhǔn)備“畫(huà)”出的那些不同圖元)。注意如下語(yǔ)法:函數(shù)定義處,若有可缺省參數(shù)的話,必須放于參數(shù)表的“最右邊”,且要連續(xù)出現(xiàn)。(2)paint成員函數(shù)中,由于pg[i]為各派生類對(duì)象的地址(由構(gòu)造函數(shù)的各實(shí)參帶來(lái)),從而使隨后的i循環(huán)可“畫(huà)”出所設(shè)計(jì)圖形的各圖元(圖元數(shù)不多于10)。
68
(3)main函數(shù)中,說(shuō)明了一個(gè)由九個(gè)圖元構(gòu)成的figure類對(duì)象fig,這九個(gè)圖元由調(diào)用構(gòu)造函數(shù)時(shí)帶去的那九個(gè)實(shí)參所確定,各實(shí)參均為指向graphelem不同派生類對(duì)象的具體指針(也即,對(duì)象地址)。(4)這個(gè)程序商不完整,缺少五個(gè)派生類中虛函數(shù)draw的具體實(shí)現(xiàn)代碼。隨C++編譯版本的不同,draw函數(shù)的具體編制方式可能不同,而這方面的內(nèi)容并不屬于C++語(yǔ)言的基本規(guī)則范圍之內(nèi)。69
8.7派生關(guān)系中的二義性處理
--參看書(shū)p199,8.2.4小節(jié)
1.單繼承時(shí)父類與子類間重名成員的處理
單繼承時(shí)父類與子類間成員重名時(shí),按如下規(guī)定進(jìn)行處理:對(duì)子類而言,不加類名限定時(shí)默認(rèn)為是處理子類成員,而要訪問(wèn)父類重名成員時(shí),則要通過(guò)類名限定。
#include<iostream.h>classCB{public:
inta; CB(intx){a=x;} voidshowa(){cout<<"ClassCB--a="<<a<<endl;}};70
classCD:publicCB{public:
inta; //與基類a同名
CD(intx,inty):CB(x){a=y;} voidshowa(){ //與基類showa同名
cout<<"ClassCD--a="<<a<<endl; }
voidprint2a(){
cout<<"a="<<a<<endl; //子類a
cout<<"CB::a="<<CB::a<<endl; //父類a }};71
voidmain(){ CBCBobj(12);
CBobj.showa(); CDCDobj(48,999);
CDobj.showa(); //子類的showa CDobj.CB::showa(); //父類的showa cout<<"CDobj.a="<<CDobj.a<<endl;
cout<<"CDobj.CB::a="<<CDobj.CB::a<<endl;}
程序執(zhí)行后的顯示結(jié)果如下:ClassCB--a=12ClassCD--a=999ClassCB--a=48CDobj.a=999CDobj.CB::a=4872
2.多繼承情況下二基類間重名成員的處理
多繼承情況下二基類間成員重名時(shí),按如下方式進(jìn)行處理:對(duì)子類而言,不加類名限定時(shí)默認(rèn)為是處理子類成員,而要訪問(wèn)父類重名成員時(shí),則要通過(guò)類名限定。
#include<iostream.h>classCB1{public:
inta; CB1(intx){a=x;} voidshowa(){cout<<"ClassCB1==>a="<<a<<endl;}};73
classCB2{public:
inta; CB2(intx){a=x;} voidshowa(){cout<<"ClassCB2==>a="<<a<<endl;}};
classCD:publicCB1,publicCB2{public:
inta;//與二基類數(shù)據(jù)成員a同名
CD(intx,inty,intz):CB1(x),CB2(y){a=z;}74
voidshowa(){ //與二基類成員函數(shù)showa同名
cout<<"ClassCD==>a="<<a<<endl; }
voidprint3a(){ //顯示出派生類的a及其二父類的重名成員a
cout<<"a="<<a<<endl;
cout<<"CB1::a="<<CB1::a<<endl;
cout<<"CB2::a="<<CB2::a<<endl; }};75
voidmain(){ CB1CB1obj(11); CB1obj.showa(); CDCDobj(101,202,909);
CDobj.showa(); //子類showa CDobj.CB1::showa(); //父類showa cout<<"CDobj.a="<<CDobj.a<<endl;
cout<<"CDobj.CB2::a="<<CDobj.CB2::a<<endl;}
程序執(zhí)行后的顯示結(jié)果如下:ClassCB1==>a=11ClassCD==>a=909ClassCB1==>a=101CDobj.a=909CDobj.CB2::a=20276
3.多級(jí)混合繼承(非虛擬繼承)
包含兩個(gè)基類實(shí)例情況的處理
多級(jí)混合繼承情況下,若類D從兩條不同“路徑”同時(shí)對(duì)類A進(jìn)行了一般性繼承(非虛擬繼承)的話,則類D的對(duì)象中會(huì)同時(shí)包含著兩個(gè)類A的實(shí)例。此時(shí),對(duì)類D而言,要通過(guò)類名限定來(lái)指定訪問(wèn)兩個(gè)類A實(shí)例中的哪一個(gè)。
本例的類間繼承關(guān)系示例如下:classAclassB:publicAclassC:publicAclassD:publicB,publicC
存儲(chǔ)結(jié)構(gòu)示意:(((A)B)((A)C
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 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ì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度冷鏈物流PPP項(xiàng)目合作協(xié)議3篇
- 二零二五年度寵物醫(yī)院獸醫(yī)藥品及醫(yī)療器械采購(gòu)合同4篇
- 2025年度醫(yī)院科室承包綜合管理與創(chuàng)新發(fā)展合同4篇
- 2025年度農(nóng)業(yè)種植與農(nóng)業(yè)品牌建設(shè)合作合同4篇
- 2025年度農(nóng)家樂(lè)特色農(nóng)產(chǎn)品銷售與品牌推廣協(xié)議4篇
- 2025年度大學(xué)教師心理健康教育聘用合同3篇
- 2025年度生態(tài)旅游項(xiàng)目土地承包合作協(xié)議范本2篇
- 2025年度擬上公司與會(huì)計(jì)事務(wù)所財(cái)務(wù)報(bào)告編制保密合同3篇
- 數(shù)字化影像處理技術(shù)-深度研究
- 2025年度生態(tài)農(nóng)業(yè)綜合開(kāi)發(fā)項(xiàng)目合同范本4篇
- 河南省濮陽(yáng)市2024-2025學(xué)年高一上學(xué)期1月期末考試語(yǔ)文試題(含答案)
- 割接方案的要點(diǎn)、難點(diǎn)及采取的相應(yīng)措施
- 2025年副護(hù)士長(zhǎng)競(jìng)聘演講稿(3篇)
- 2024年08月北京中信銀行北京分行社會(huì)招考(826)筆試歷年參考題庫(kù)附帶答案詳解
- 原發(fā)性腎病綜合征護(hù)理
- (一模)株洲市2025屆高三教學(xué)質(zhì)量統(tǒng)一檢測(cè) 英語(yǔ)試卷
- 基礎(chǔ)護(hù)理學(xué)導(dǎo)尿操作
- DB11∕T 1028-2021 民用建筑節(jié)能門(mén)窗工程技術(shù)標(biāo)準(zhǔn)
- (初級(jí))航空油料計(jì)量統(tǒng)計(jì)員技能鑒定理論考試題庫(kù)(含答案)
- 執(zhí)業(yè)藥師勞動(dòng)合同范本
- 2024年高考英語(yǔ)復(fù)習(xí)(新高考專用)完形填空之詞匯復(fù)現(xiàn)
評(píng)論
0/150
提交評(píng)論