C++語言-南開大學ch8第 8章 繼承與派生_第1頁
C++語言-南開大學ch8第 8章 繼承與派生_第2頁
C++語言-南開大學ch8第 8章 繼承與派生_第3頁
C++語言-南開大學ch8第 8章 繼承與派生_第4頁
C++語言-南開大學ch8第 8章 繼承與派生_第5頁
已閱讀5頁,還剩82頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第8章繼承與派生8.1派生類的定義及其構造和析構函數(shù)8.2派生類使用例--公司雇員檔案的管理8.3多態(tài)性與虛函數(shù)8.4虛函數(shù)使用例1--計算函數(shù)的定積分8.5與基類對象和派生類對象相關的賦值兼容性問題8.6虛函數(shù)使用例2--利用圖元類畫圖8.7派生關系中的二義性處理8.8虛基類

1C++程序用不同的類定義來表示一組數(shù)據(jù)以及對這些數(shù)據(jù)的操作與處理,而類之間往往具有某種關系,“繼承與派生”就是類間的一種常用關系。

例如,交通工具→汽車→轎車→紅旗轎車。

具有層次關系!汽車 是一種特殊的交通工具轎車 是一種特殊的汽車紅旗轎車是一種特殊的轎車2

只要定義清楚了“交通工具”,那么在定義“汽車”時(注意,它就是交通工具),只需再說明它的特殊性(而不必重新從頭定義?。?。同理,只要定義清楚了“轎車”,那么在定義“紅旗轎車”時(注意,它就是轎車),只需再說明它的特殊性(根本不必重新從頭定義!)。

又例如,公司四種雇員檔案的管理:

employee(雇員):姓名、年齡、工資;

manager(經(jīng)理):姓名、年齡、工資、行政級別;

engineer(工程師):姓名、年齡、工資、專業(yè)、學位;

director(高級主管):姓名、年齡、工資、專業(yè)、學位、職務。3

C++提供了類定義的派生和繼承功能,能很好地解決上述問題(使代碼可重用,避免重復?。?。

若類A是類B的基類(父類),則類B是類A的派生類(子類)。也可以說,類B(子類)繼承了類A(父類);或說,類A(父類)派生出類B(子類)。4 8.1派生類的定義及其構造和析構函數(shù)

--參看書p193-197,8.2.1與8.2.2小節(jié)1.派生類的定義

class<派生類類型名>:<基類表>{

private: <各私有成員說明>;

public: <各公有成員說明>;

protected: <各保護成員說明>; <以關鍵字friend開頭的友元說明>;};

5

<基類表>的一般格式為:

<派生方式><基類名1>,...,<派生方式><基類名n>

而<派生方式>又可為private、public或protected。6

派生方式(基類 在基類中的在派生類中的被繼承方式)存取權限 的存取權限==================================================

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派生方式:使基類的公有成員和保護成員在派生類中仍然是公有成員和保護成員,而基類的私有成員不可在派生類中被存取。

protected派生方式:使基類的公有成員和保護成員在派生類中都變?yōu)楸Wo成員,而基類的私有成員不可在派生類中被存取。

private派生方式:使基類的公有成員和保護成員在派生類中都變?yōu)樗接谐蓡T,而基類的私有成員不可在派生類中被存取。

8派生類中可出現(xiàn)四種成員:

1)不可訪問的成員--基類的private私有成員被繼承過來后,這些成員在派生類中是不可訪問的。

2)私有成員--包括在派生類中新增加的private私有成員以及從基類私有繼承過來的某些成員。這些成員在派生類中是可以訪問的。

3)保護成員--包括在派生類中新增加的potected保護成員以及從基類繼承過來的某些成員。這些成員在派生類中是可以訪問的。

4)公有成員--包括在派生類中新增加的public公有成員以及從基類公有繼承過來的基類的public成員。這些成員不僅在派生類中可以訪問,而且在建立派生類對象的模塊中,也可以通過對象來訪問它們。9

分析下述程序中的繼承與派生關系,并上機進行測試驗證,以加深對它們進行正確使用的理解。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.派生類的構造函數(shù)和析構函數(shù)

派生類的構造函數(shù)的一般格式如下:

<派生類名>(<參數(shù)總表>):<初始化符表> { <構造函數(shù)體> }

而<初始化符表>按如下格式構成:<基類名1>(<基類參數(shù)表1>),...,<基類名n>(<基類參數(shù)表n>),<對象成員名1>(<對象成員參數(shù)表1>),...,<對象成員名m>(<對象成員參數(shù)表m>)

(注:若無對象成員時,則不出現(xiàn)此后半部分;基類名與對象成員名的次序無關緊要,各自出現(xiàn)的順序可以任意)

18派生類構造函數(shù)執(zhí)行的一般次序如下:(1)調用各基類的構造函數(shù),調用順序繼承時的聲明順序。(2)若派生類含有對象成員的話,調用各對象成員的構造函數(shù),調用順序按照聲明順序。(3)執(zhí)行派生類構造函數(shù)的函數(shù)體。析構派生類對象時,其執(zhí)行次序恰與構造時的次序相反。19

//改造書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運行結果為:CB::b=4CC::c=6CD::d=2CDobjisdestructingCCobjisdestructingCBobjisdestrcting

思考:將派生類CD改寫為如下形式后,請給出輸出結果。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派生類使用例--公司雇員檔案的管理

--參看書p190-193,8.1節(jié)

假設公司雇員分為:雇員(employee)、經(jīng)理(manager)、工程師(engineer)、高級主管(director)。而且假定只關心這幾類雇員各自的如下一些數(shù)據(jù):

employee(雇員)類:姓名、年齡、工資;

manager(經(jīng)理)類:姓名、年齡、工資、行政級別;

engineer(工程師)類:姓名、年齡、工資、專業(yè)、學位;

director(高級主管)類:姓名、年齡、工資、專業(yè)、學位、職務。25

(具體程序見書p190--193)

#include<iostream.h>#include<string.h>classemployee{//employee類(類型),將作為其它幾個類的基類

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){ //對基類初始化負責

level=lev; }

voidprint()const{ employee::print();//調用基類print顯示“共性”數(shù)據(jù)

cout<<"level:"<<level<<endl; } };28

/*注意:允許派生類中的print與基類的print重名,按如下規(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(); //調用基類的print eng.print(); dir.print();}30程序執(zhí)行后的顯示結果如下:

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ù)

--參看書p200,8.3節(jié)

1.函數(shù)重載(overloading)與靜態(tài)聯(lián)編(staticbinding)

函數(shù)重載(overloading)指的是,允許多個不同函數(shù)使用同一個函數(shù)名,但要求這些同名函數(shù)具有不同的參數(shù)表。.參數(shù)表中的參數(shù)個數(shù)不同;.參數(shù)表中對應的參數(shù)類型不同;.參數(shù)表中不同類型參數(shù)的次序不同。32

例:

int

abs(intn){ return(n<0?-n:n); }

floatabs(floatn) { if(f<0)f=-f; returnf; }

系統(tǒng)對函數(shù)重載這種多態(tài)性的分辨與處理,是在編譯階段完成的--靜態(tài)聯(lián)編(staticbinding)。33

2.函數(shù)超載(overriding)、虛函數(shù)(virtualfunction)及動態(tài)聯(lián)編(dynamicbinding)

(1)函數(shù)超載(overriding)

.僅在基類與其派生類的范圍內實現(xiàn);.允許多個不同函數(shù)使用完全相同的函數(shù)名、函數(shù)參數(shù)表以及函數(shù)返回類型;

34

(2)虛函數(shù)(virtualfunction)

.在定義某一基類(或其派生類)時,若將其中的某一函數(shù)成員的屬性說明為virtual,則稱該函數(shù)為虛函數(shù)(virtualfunction)。.虛函數(shù)的使用與函數(shù)超載密切相關。若基類中某函數(shù)被說明為虛函數(shù),則意味著其派生類中也要用到與該函數(shù)同名、同參數(shù)表、同返回類型、但函數(shù)(實現(xiàn))體不同的這同一個所謂的超載函數(shù)。35

classgraphelem{protected:

intcolor;public:

graphelem(intcol){ color=col; } virtualvoiddraw(){...};//虛函數(shù)draw,每一個類都要“draw”出屬于它的類對象圖形};

36classline:publicgraphelem{public: virtualvoiddraw(){...};//虛函數(shù)draw,負責畫出“l(fā)ine” ...};

classcircle:publicgraphelem{public: virtualvoiddraw(){...};//虛函數(shù)draw,負責畫出“circle” ...};

37classtriangle:publicgraphelem{public: virtualvoiddraw(){...};//虛函數(shù)draw,負責畫出“triangle” ...};

(3)動態(tài)聯(lián)編(dynamicbinding)

與虛函數(shù)以及程序中使用指向基類的指針(變量)密切相關。注意:C++規(guī)定,基類指針可以指向其派生類的對象(也即,可將派生類對象的地址賦給其基類指針變量),但反過來不可以。這一點正是函數(shù)超載及虛函數(shù)用法的基礎。38

例1.建立上述類line、類circle以及類triangle的類對象,而后調用它們各自的draw函數(shù)“畫出”它們。

方法1:直接通過類對象(由類對象可以唯一確定要調用哪一個類的draw函數(shù))

lineln1; circlecir1; triangletri1;ln1.draw(); cir1.draw(); tri1.draw();39

方法2:使用指向基類的指針(動態(tài)聯(lián)編,要靠執(zhí)行程序時其基類指針的“動態(tài)”取值來確定調用哪一個類的draw函數(shù))

graphelem*pObj;lineln1; circlecir1; triangletri1;

pObj=&lin1; pObj->draw();

pObj=&cir1; pObj->draw();

pObj=&tri1; pObj->draw();

40

例2.假設inte_algo為基類,其中說明了一個虛函數(shù)integrate,并在其三個派生類中,也說明了該虛函數(shù)integrate(使用不同方法計算定積分)。

那么,可使用函數(shù)integrateFunc來實現(xiàn)調用不同虛函數(shù)integrate的目的:

voidintegrateFunc(inte_algo*p){

//基類指針p可指向任一派生類的對象

p->integrate();

//調用的將是不同派生類的integrate函數(shù)}

主調函數(shù)處使用:integrateFunc(<某派生類的類對象地址>);41

在編譯階段,系統(tǒng)無法確定究竟要調用哪一個派生類的integrate。此種情況下,將采用動態(tài)聯(lián)編方式來處理:在運行階段,通過p指針的當前值,去動態(tài)地確定對象所屬類,而后找到對應虛函數(shù)。

3.純虛函數(shù)與抽象基類

如果不準備在基類的虛函數(shù)中做任何事情,則可使用如下的格式將該虛函數(shù)說明成純虛函數(shù):

virtual<函數(shù)原型>=0;42

純虛函數(shù)不能被直接調用,它只為其派生類的各虛函數(shù)規(guī)定了一個一致的“原型規(guī)格”(該虛函數(shù)的實現(xiàn)將在它的派生類中給出)。

含有純虛函數(shù)的基類稱為抽象基類。注意,不可使用抽象基類來說明并創(chuàng)建它自己的對象,只有在創(chuàng)建其派生類對象時,才有抽象基類自身的實例伴隨而生。

實際上,抽象基類是其各派生類之共同點的一個抽象綜合,通過它,再“加上”各派生類的特有成員以及對基類中那一純虛函數(shù)的具體實現(xiàn),方可構成一個具體的實用類型。

另外:如果一個抽象基類的派生類中沒有定義基類中的那一純虛函數(shù)、而只是繼承了基類之純虛函數(shù)的話,則這個派生類還是一個抽象基類(其中仍包含著繼承而來的那一個純虛函數(shù))。43

8.4虛函數(shù)使用例1--計算函數(shù)的定積分

--參看書p205-208,8.4.1小節(jié)

采用矩形法、梯形法以及simpson法來計算同一函數(shù)的定積分。

此三種方法均將區(qū)間[a,b]分為n等份,而后以不同方式求出各小段對應的小面積s[i],并將它們相加到一起來作為近似結果。

#include<iostream.h>

floatfunction(floatx){//欲積分的函數(shù)

return4.0/(1+x*x);}44

classinte_algo{protected: floata,b; //a,b為積分區(qū)間的左右邊界

intn; //n表示把[a,b]劃分成多少個小區(qū)段進行積分

floath,sum;//h表示步長,sum表示積分結果值

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); //派生類中說明同一個虛函數(shù)integrate};46

classladder:publicinte_algo{ ...};

classsimpson:publicinte_algo{ ...};

voidinte_algo::integrate(){ ...}47

voidrectangle::integrate(){ /*

派生類rectangle之虛函數(shù)integrate的類外定義,采用矩形法來計算函數(shù)的定積分。計算公式為:

sum=(f(a)+f(a+h)+f(a+2h)+...+f(a+(n-1)h))h */

floatal=a; /*al為調用f函數(shù)時的實參值,依次取值a,a+h,a+2h,...,a+(n-1)h。 */48for(inti=0;i<n;i++)//共在n個點處計算函數(shù)值{

sum+=function(al); al+=h; //al每次增加一個步長h }; sum*=h;

cout<<sum<<endl; //顯示積分結果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í)行后的顯示結果如下:inputanum(1--rectanglemethod,2--laddermethod,3--simpsonmethod)3simpsonmethod:suum==>3.1415952

注:也可將上述的integrateFunc函數(shù)以及main用如下樣式的一個main函數(shù)來替代。voidmain(){ rectanglerec(0.0,1.0,10); …

cin>>ii; switch(ii){ case1:{//矩形法

cout<<"rectanglemethod:suum==>"; p=&rec; break; } case2:{//梯形法 ... }

case3:{//simpson法 ... } }

p->integrate();}

53

當然,若只為實現(xiàn)上述功能(任務),完全可以不用指針,而直接通過類對象來進行調用(此時將不再通過動態(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與基類對象和派生類對象相關的賦值兼容性問題

1.基類對象=派生類對象; //OK!

派生類對象=基類對象; //ERROR!

2.指向基類型的指針=派生類對象的地址;//OK!

指向派生類類型的指針=基類對象的地址; //ERROR!

注:訪問非基類成員部分時,要經(jīng)過指針類型的強制轉換。

3.基類的引用=派生類對象; //OK!

派生類的引用=基類對象; //ERROR!

注:通過引用只可以訪問基類成員部分。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!--訪問非基類成員部分

cout<<((derived*)pb)->getb()<<endl; //OK!--經(jīng)過類型轉換 //derived*pd=&bs1; //ERR!}57

8.6虛函數(shù)使用例2--利用圖元類畫圖

--參看書p208-212,8.4.2小節(jié)本程序自定義pixel、graphelem、line、rectangle、triangle、circle、square、figure等8個類(類型)并對它們進行使用。

實現(xiàn)要點:

1.設立并處理以下圖元:直線(line類),矩形(rectangle類),三角形(triangle類),圓(circle類),正方形(square類)。2.將每一種圖元設計成一個類,在每一個類的定義中,除含有其構造函數(shù)外,還包含一個可將本類的圖元畫出來的公有函數(shù)draw。

58

3.由于每一個圖元都要用到顏色(color)數(shù)據(jù)成員,所以設立一個基類graphelem,它含有protected型數(shù)據(jù)成員color,以及一個虛函數(shù)draw。

4.

由于不準備在基類graphelem的虛函數(shù)draw中做任何事情,所以在其原型后加上“=0”字樣而構成純虛函數(shù)。從而使graphelem成為抽象基類。

5.程序中至少要設立具有以下關系的六個類:抽象基類graphelem;由graphelem直接派生出的四個類:line,rectangle,triangle,circle;由rectangle派生出一個類:square。

6.由于“畫”以上圖元時,都要用到“點”的概念與位置,所以設立的第七個類為:pixel。59

7.

為了通過虛函數(shù)進行動態(tài)聯(lián)編處理,需說明并使用指向基類graphelem的指針(注,該程序中說明了10個這種指針,放在一個稱為pg的數(shù)組中,既是說,pg[0],pg[1],...,pg[9]均為這種指向基類graphelem的指針)。而后通過這些指針的動態(tài)取值(使它們指向不同的派生類),進而利用函數(shù)調用“pg[i]->draw()”(i=0,1,...,9)來“畫”出組成一個圖形的不同圖元來。本程序中的第八個類figure(中的paint成員函數(shù))正是用來完成上述“畫”圖元功能的。

雖然pixel,figure這兩個類與其它六個類沒有繼承和派生的關系,但卻有成員關系。類pixel的對象要作為graphelem及其派生類的成員和構造函數(shù)成員的參數(shù)。而類figure則以graphelem類的對象指針數(shù)組作為其數(shù)據(jù)成員。60

#include<iostream.h>classpixel{ //類pixel,表示屏幕像素點

intx,y;public: pixel(){ //構造函數(shù)一,無參

x=0; y=0; } pixel(inta,intb){ //構造函數(shù)二,參數(shù)a、b表示點的位置

x=a; y=b; } pixel(constpixel&p){ //構造函數(shù)三,參數(shù)p為某個已存在對象

x=p.x; y=p.y; }

intgetx(){returnx;} //獲取對象的x值

intgety(){returny;} //獲取對象的y值};

61

enumcolort{ //枚舉類型,用于定義顏色常量(名字)

black,blue,green,cyan,red,magenta,brown,

lightgray,darkgray,lightblue,lightgreen,

lightcyan,lightred,lightmagenta,yellow,white,blink};

classgraphelem{ //基類graphelem(實際為抽象基類)protected:colortcolor; //顏色colorpublic:graphelem(colortcol){ color=col; } virtualvoiddraw()=0; //純虛函數(shù)draw

};62

classline:publicgraphelem{ //派生類line pixelstart,end; //成員為pixel類對象

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{//通過它的paint函數(shù)可“畫”出組成一個圖形的各圖元

graphelem*pg[10]; //pg數(shù)組含有10個指向基類的指針

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ù)默認值的構造函數(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(){ //“畫”出圖形的各圖元

for(inti=0;i<10;i++) if(pg[i]!=0) pg[i]->draw(); };};

66

voidmain(){ //說明9個類對象(圖元),它們是構成一個圖形的九個“部件”

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); //長方

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(); //調用paint函數(shù),“畫”出fig對象的9個圖元}67

程序說明:(1)figure類的構造函數(shù),含有10個參數(shù),且該10個參數(shù)均為可缺省參數(shù)(被賦了缺省值的參數(shù),調用時,相應實參可缺?。?。說明figure類對象時,其實參可為10個(或少于10個)指向graphelem不同派生類對象的具體指針(注意,C++允許基類指針指向其派生類對象;而此處的各派生類對象正是準備“畫”出的那些不同圖元)。注意如下語法:函數(shù)定義處,若有可缺省參數(shù)的話,必須放于參數(shù)表的“最右邊”,且要連續(xù)出現(xiàn)。(2)paint成員函數(shù)中,由于pg[i]為各派生類對象的地址(由構造函數(shù)的各實參帶來),從而使隨后的i循環(huán)可“畫”出所設計圖形的各圖元(圖元數(shù)不多于10)。

68

(3)main函數(shù)中,說明了一個由九個圖元構成的figure類對象fig,這九個圖元由調用構造函數(shù)時帶去的那九個實參所確定,各實參均為指向graphelem不同派生類對象的具體指針(也即,對象地址)。(4)這個程序商不完整,缺少五個派生類中虛函數(shù)draw的具體實現(xiàn)代碼。隨C++編譯版本的不同,draw函數(shù)的具體編制方式可能不同,而這方面的內容并不屬于C++語言的基本規(guī)則范圍之內。69

8.7派生關系中的二義性處理

--參看書p199,8.2.4小節(jié)

1.單繼承時父類與子類間重名成員的處理

單繼承時父類與子類間成員重名時,按如下規(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í)行后的顯示結果如下:ClassCB--a=12ClassCD--a=999ClassCB--a=48CDobj.a=999CDobj.CB::a=4872

2.多繼承情況下二基類間重名成員的處理

多繼承情況下二基類間成員重名時,按如下方式進行處理:對子類而言,不加類名限定時默認為是處理子類成員,而要訪問父類重名成員時,則要通過類名限定。

#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í)行后的顯示結果如下:ClassCB1==>a=11ClassCD==>a=909ClassCB1==>a=101CDobj.a=909CDobj.CB2::a=20276

3.多級混合繼承(非虛擬繼承)

包含兩個基類實例情況的處理

多級混合繼承情況下,若類D從兩條不同“路徑”同時對類A進行了一般性繼承(非虛擬繼承)的話,則類D的對象中會同時包含著兩個類A的實例。此時,對類D而言,要通過類名限定來指定訪問兩個類A實例中的哪一個。

本例的類間繼承關系示例如下:classAclassB:publicAclassC:publicAclassD:publicB,publicC

存儲結構示意:(((A)B)((A)C

溫馨提示

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

評論

0/150

提交評論