面向?qū)ο笳n件第八章_第1頁
面向?qū)ο笳n件第八章_第2頁
面向?qū)ο笳n件第八章_第3頁
面向?qū)ο笳n件第八章_第4頁
面向?qū)ο笳n件第八章_第5頁
已閱讀5頁,還剩89頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

面向?qū)ο笳n件第八章第一頁,共九十四頁,編輯于2023年,星期五第八章多態(tài)性

§8.1多態(tài)性的基本概念

§8.2函數(shù)重載

§8.3拷貝構(gòu)造函數(shù)

§8.4運(yùn)算符重載

§8.5虛函數(shù)

§8.6純虛函數(shù)與抽象類第二頁,共九十四頁,編輯于2023年,星期五§8.1多態(tài)性的基本概念在基類中定義的屬性或操作被派生類繼承之后,可以具有不同的數(shù)據(jù)類型或表現(xiàn)出不同的行為,從而同一個(gè)屬性或操作名稱在各個(gè)派生類中具有不同的含義ManagerWifeAssistantSecretary第三頁,共九十四頁,編輯于2023年,星期五§8.1多態(tài)性的基本概念

C++語言支持兩種多態(tài)性編譯時(shí)的多態(tài)性 通過重載實(shí)現(xiàn)(函數(shù)重載,運(yùn)算符重載)運(yùn)行時(shí)的多態(tài)性 通過虛函數(shù)實(shí)現(xiàn)(借助抽象類和動(dòng)態(tài)綁定)第四頁,共九十四頁,編輯于2023年,星期五§8.1多態(tài)性的基本概念綁定 將一個(gè)函數(shù)調(diào)用鏈接上相應(yīng)的函數(shù)體代碼 的過程靜態(tài)綁定 在編譯時(shí)就能夠確定調(diào)用哪一個(gè)函數(shù)動(dòng)態(tài)綁定 在運(yùn)行時(shí)才能夠確定調(diào)用哪一個(gè)函數(shù)第五頁,共九十四頁,編輯于2023年,星期五§8.1多態(tài)性的基本概念本章重點(diǎn)

重載:函數(shù)重載,運(yùn)算符重載 靜態(tài)綁定

虛函數(shù):抽象類 動(dòng)態(tài)綁定第六頁,共九十四頁,編輯于2023年,星期五§8.2函數(shù)重載函數(shù)重載(函數(shù)名相同,函數(shù)參數(shù)不同)voidprint(char);voidprint(int,int);voidprint(float);voidprint(char*);……函數(shù)調(diào)用print(“Hello,overload!”);print(3,5);第七頁,共九十四頁,編輯于2023年,星期五§8.2函數(shù)重載類構(gòu)造函數(shù)的重載

classA { public: A(); A(int); A(charc); //…… }; Aaa(34);第八頁,共九十四頁,編輯于2023年,星期五§8.2函數(shù)重載

函數(shù)重載的注意事項(xiàng)

⑴參數(shù)不同,是指參數(shù)的個(gè)數(shù),參數(shù)的類型不同

⑵只有返回值類型不同,不是函數(shù)重載

⑶不要用重載函數(shù)描述毫不相干的函數(shù)

⑷在重載函數(shù)中使用缺省參數(shù)時(shí)應(yīng)注意二義性問題第九頁,共九十四頁,編輯于2023年,星期五§8.2函數(shù)重載例:

voidprint(inta,intb) { …… } voidprint(inta,intb,intc) { …… }函數(shù)說明:voidprint(inta,intb,intc=50);函數(shù)調(diào)用:print(10,100); //error!系統(tǒng)不知調(diào)用哪個(gè)函數(shù)第十頁,共九十四頁,編輯于2023年,星期五§8.2函數(shù)重載例:參數(shù)類型不同

floatabs(floatx) { …… } doubleabs(doublex) { …… }

函數(shù)調(diào)用:abs(5);//error!

因?yàn)橄到y(tǒng)不知應(yīng)將5轉(zhuǎn)換成float,還是double第十一頁,共九十四頁,編輯于2023年,星期五§8.2函數(shù)重載 在函數(shù)調(diào)用時(shí),如找不到與實(shí)參完全匹配的函數(shù)原型,C++的隱式類型轉(zhuǎn)換如能將一個(gè)類型轉(zhuǎn)為能與函數(shù)原型匹配,則選擇調(diào)用該重載函數(shù) 例: 函數(shù)原型:intfunc(doubled);

函數(shù)調(diào)用:func(‘A’); //系統(tǒng)自動(dòng)將‘A’(字符型)轉(zhuǎn)換成double第十二頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)

構(gòu)造對(duì)象的兩個(gè)特殊構(gòu)造函數(shù)默認(rèn)構(gòu)造函數(shù)(復(fù)習(xí))2.拷貝構(gòu)造函數(shù)第十三頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)默認(rèn)構(gòu)造函數(shù) 例:Aaa;//當(dāng)定義一個(gè)對(duì)象而不給它任何初始 值時(shí),系統(tǒng)就要調(diào)用默認(rèn)構(gòu)造函數(shù)默認(rèn)構(gòu)造函數(shù): 參數(shù)表為空或所有參數(shù)都有默認(rèn)值的構(gòu)造函數(shù) 如:A();或A(inti=0,intj=5);第十四頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)

遇下列情況系統(tǒng)自動(dòng)調(diào)用默認(rèn)構(gòu)造函數(shù)來構(gòu)造對(duì)象 ⑴直接定義一個(gè)對(duì)象而沒有給初始值 例:Aaa; ⑵用new動(dòng)態(tài)申請(qǐng)的對(duì)象而沒有給初始值 例:A*pa=newA;

或:A*pa; pa=newA; ⑶定義了一個(gè)對(duì)象數(shù)組 例:Aarray[10];

第十五頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)默認(rèn)構(gòu)造函數(shù)的作用 為了讓所定義的類能夠被使用(有時(shí)甚至沒有給對(duì)象任何初始化信息)當(dāng)所定義的類沒有提供任何構(gòu)造函數(shù)時(shí),系統(tǒng)將為類自動(dòng)生成一個(gè)默認(rèn)構(gòu)造函數(shù)第十六頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)只要定義了一個(gè)構(gòu)造函數(shù),系統(tǒng)將不再生成默認(rèn)構(gòu)造函數(shù) 例:classA { A(inti); …… };

如下定義類A的對(duì)象:

Aaa; Aarray[10]; A*pa=newA;一般情況下,都要定義自己的構(gòu)造函數(shù),并至少定義一個(gè)默認(rèn)構(gòu)造函數(shù)第十七頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù) 拷貝構(gòu)造函數(shù)的作用用一個(gè)對(duì)象去構(gòu)造另一個(gè)同類的對(duì)象 例:

STUDENTs1(“Jenny”);

//系統(tǒng)調(diào)用構(gòu)造函數(shù)

STUDENTs2=s1;

//系統(tǒng)調(diào)用拷貝構(gòu)造函數(shù),用對(duì) 象s1的值去初始化對(duì)象s2對(duì)象作為函數(shù)參數(shù)對(duì)象作為函數(shù)返回值第十八頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)拷貝構(gòu)造函數(shù)的形式(STUDENT類)

STUDENT(constSTUDENT&obj); { …… }用obj初始化一個(gè)新對(duì)象第十九頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)拷貝構(gòu)造函數(shù)的說明:⑴拷貝構(gòu)造函數(shù)只有一個(gè)參數(shù),用同一類的對(duì)象作參數(shù)⑵參數(shù)傳遞方式必須按引用調(diào)用函數(shù)⑶每個(gè)類都必須有一個(gè)拷貝構(gòu)造函數(shù),如果沒定義,系 統(tǒng)自動(dòng)生成一個(gè)缺省的拷貝構(gòu)造函數(shù)缺省拷貝構(gòu)造函數(shù)的含義: 用一個(gè)已知對(duì)象的數(shù)據(jù)成員的值拷貝給正在創(chuàng)建的另一個(gè)同類的對(duì)象第二十頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)拷貝構(gòu)造函數(shù)在下列情況被系統(tǒng)自動(dòng)調(diào)用:⑴當(dāng)一個(gè)對(duì)象以聲明初始化的方式復(fù)制時(shí) 如:STUDENTs2=s1;⑵當(dāng)一個(gè)對(duì)象作為參數(shù)傳遞給一個(gè)函數(shù)時(shí) 例:voidmain() { STUDENTms; func(ms); } voidfunc(STUDENTfs) { …… } //調(diào)用拷貝構(gòu)造函數(shù)將實(shí)參

ms對(duì)象的副本拷貝給fs//func()函數(shù)調(diào)用結(jié)束返回時(shí),還要析構(gòu)fs第二十一頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)⑶當(dāng)一個(gè)對(duì)象作為值從一個(gè)函數(shù)返回時(shí)

例:STUDENTfunc() {

STUDENTms(“Randy”);

returnms; } voidmain() { STUDENTs; s=func();

}

函數(shù)func的棧區(qū)main函數(shù)的棧區(qū)mss臨時(shí)對(duì)象放入取出//系統(tǒng)調(diào)用拷貝構(gòu)造函數(shù),將ms

拷貝到新創(chuàng)建的臨時(shí)對(duì)象中第二十二頁,共九十四頁,編輯于2023年,星期五例:分析程序執(zhí)行結(jié)果(拷貝構(gòu)造函數(shù)舉例)classSTUDENT{ public: STUDENT(char*pn=“noname”,intsid=0) { id=sid; strcpy(name,pn); cout<<“constructingnewstudent”<<name<<endl; } STUDENT(constSTUDENT&s) //拷貝構(gòu)造函數(shù)

{ cout<<“constructingcopyof”<<<<endl; strcpy(name,“copyof”); strcat(name,); id=s.id; } ~STUDENT() {cout<<“Destructing”<<name<<endl; } protected: charname[40]; intid;};第二十三頁,共九十四頁,編輯于2023年,星期五

voidfn(STUDENTs) { cout<<“Infunctionfn()\n”; } voidmain() { STUDENTrandy(“Randy”,1234); cout<<“callingfn()\n”; fn(randy); cout<<“Returnedfromfn()\n”; }第二十四頁,共九十四頁,編輯于2023年,星期五程序執(zhí)行結(jié)果:constructingnewstudentRandy //調(diào)用普通構(gòu)造函數(shù)callingfn() //main()函數(shù)中的輸出constructingcopyofRandy //調(diào)用拷貝構(gòu)造函數(shù)Infunctionfn() //fn()函數(shù)中的輸出DestructingcopyofRandy //從fn函數(shù)返回時(shí),形參s被析構(gòu)Returnedfromfn() //回到main函數(shù)后的輸出DestructingRandy //main函數(shù)執(zhí)行結(jié)束時(shí),對(duì)象randy被析構(gòu)第二十五頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)

淺拷貝與深拷貝(shallowcopy與deepcopy)淺拷貝(見下圖)pName堆p1pNamepName堆p1p2淺拷貝:創(chuàng)建p2時(shí),對(duì)象p1被復(fù)制給了p2,但資源并 未復(fù)制,p1,p2指向同一資源默認(rèn)拷貝構(gòu)造函數(shù)是淺拷貝(淺拷貝是不安全的)拷貝前拷貝后第二十六頁,共九十四頁,編輯于2023年,星期五§8.3拷貝構(gòu)造函數(shù)深拷貝(見下圖)pName堆p1pNamepName堆p1p2堆拷貝前拷貝后深拷貝:對(duì)象p1被復(fù)制給p2時(shí),不但拷貝成員,也拷貝資源自己定義拷貝構(gòu)造函數(shù),在函數(shù)體中用new動(dòng)態(tài)申請(qǐng)內(nèi)存,以實(shí)現(xiàn)深拷貝第二十七頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載運(yùn)算符重載的概念友元的概念成員函數(shù)與友元函數(shù)

小結(jié)第二十八頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載運(yùn)算符重載的含義

對(duì)C++預(yù)定義的運(yùn)算符功能的擴(kuò)展 例:

QUEUEq1,q2; q1=q1+q2;

MATRIXm1,m2,m; m=m1*m2;

COUNTERc; c++;對(duì)象作操作數(shù)第二十九頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載運(yùn)算符重載的目的

增加程序的可讀性,簡潔,直接,易理解 例:

q1.addqueue(q2); q1=q1+q2; m=multimatrix(m1,m2); m=m1*m2; IncCounter(c); c++;看起來簡單與數(shù)學(xué)公式相似成員函數(shù)可以用成員函數(shù)來實(shí)現(xiàn)運(yùn)算符重載第三十頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載可以重載的運(yùn)算符 幾乎所有的C++預(yù)定義的運(yùn)算符都可以被重載

(都可以為自己定義的類重載,即用對(duì)象作為這些運(yùn)算符 的操作數(shù)參與運(yùn)算)不可以重載的運(yùn)算符

圓點(diǎn)運(yùn)算符.

域運(yùn)算符::

間接訪問運(yùn)算符* 指針成員運(yùn)算符 條件運(yùn)算符?:第三十一頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載重載運(yùn)算符的定義

返回類型operator運(yùn)算符(參數(shù)表)例:要重載運(yùn)算符“+”

返回類型

operator+(類型1參數(shù)1,類型2參數(shù)2)例:要重載運(yùn)算符“++”

返回類型operator++(類型參數(shù))可以改變可以改變但參數(shù)個(gè)數(shù)不能變是運(yùn)算符不是函數(shù)第三十二頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

運(yùn)算符重載時(shí)應(yīng)遵守的規(guī)則重載的運(yùn)算符至少有一個(gè)參數(shù)的類型與自定義的類有關(guān)(即重載的運(yùn)算符的參數(shù)不能都是預(yù)定義的數(shù)據(jù)類型)重載時(shí),運(yùn)算符的優(yōu)先級(jí)、結(jié)合性以及參數(shù)的個(gè)數(shù)不能改變不能創(chuàng)造新的運(yùn)算符第三十三頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載友元的概念 可以訪問類的保護(hù)、私有成員的函數(shù)或類如果一個(gè)函數(shù)與某個(gè)類關(guān)系密切,可以定義其為友元函數(shù)如果一個(gè)類與某個(gè)類關(guān)系密切,可以定義其為友元類第三十四頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載使用友元的目的 提高程序的運(yùn)行效率

類的數(shù)據(jù)成員大部分為私有成員,只能通過成員函數(shù)去訪問,當(dāng)對(duì)某些成員函數(shù)需多次調(diào)用時(shí),會(huì)影響程序的運(yùn)行效率第三十五頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載友元的定義(聲明)

友元是一種定義在類外部的普通函數(shù)或類,但它需要在類體內(nèi)進(jìn)行聲明第三十六頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載聲明一個(gè)函數(shù)f()是另一個(gè)類B的友元函數(shù)的方式

classB {

friend函數(shù)f()的原型;

//其它類成員的定義或聲明;

};聲明一個(gè)類A是另一個(gè)類B的友元類的方式

classB {

friendclassA;

//其它類成員的定義或聲明;

};第三十七頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載當(dāng)將一個(gè)函數(shù)f()或一個(gè)類A聲明為另一個(gè)類B的友元后,f()或類A就可以直接訪問類B的任何成員,包括私有和保護(hù)成員友元函數(shù)f()與友元類A的定義、調(diào)用等與普通函數(shù)、普通類完全一樣第三十八頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

友元通常應(yīng)用在下列情況一個(gè)函數(shù)需要經(jīng)常且大量的訪問一個(gè)類的數(shù)據(jù)成員時(shí)運(yùn)算符重載 為了能直接對(duì)對(duì)象進(jìn)行加減乘除等各種運(yùn)算,經(jīng)常需要將所定義的運(yùn)算符運(yùn)算函數(shù)聲明為類的友元函數(shù),以便可方便地訪問類的私有成員一個(gè)類從屬于另一個(gè)類時(shí) (經(jīng)常需要將一個(gè)類定義為另一個(gè)類的友元)第三十九頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

使用友元的注意事項(xiàng)friend是單向的 如果類A是類B的友元,則類A可以訪問類B的私有成員,但反之不成友元不是類的成員 友元不受類成員訪問控制的限制,沒有公有、保護(hù)、私有之分,它只是一個(gè)說明,可以放在類體內(nèi)的任何地方一個(gè)類的成員函數(shù)也可以成為另一個(gè)類的友元函數(shù),此時(shí)的友元聲明需要加上類域的限定第四十頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載例:將函數(shù)func()和類A的成員函數(shù)memfun()同時(shí)聲明為類B的友元

intfunc(int,float); //一個(gè)普通函數(shù)

classA { public:

voidmemfunc(char*); //類A的成員函數(shù)

//…… }; classB { friendintfunc(int,float); friengvoidA::memfunc(char*); //類B的其它成員

};注:友元的引用會(huì)破壞類的封裝性,使用時(shí)應(yīng)權(quán)衡利弊第四十一頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

運(yùn)算符重載的函數(shù)可采用兩種方式:成員函數(shù)與友元函數(shù)

可以將運(yùn)算符函數(shù)定義成類的成員函數(shù)

也可以將運(yùn)算符函數(shù)定義成友元函數(shù)第四十二頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載 成員函數(shù)與友元函數(shù)的比較成員函數(shù)有一個(gè)隱含的參數(shù)(this指針)

如果將一個(gè)二元運(yùn)算符定義為類的成員函數(shù),則只需為這個(gè)函數(shù)說明一個(gè)參數(shù)。 如果將一個(gè)一元運(yùn)算符定義為類的成員函數(shù),則這個(gè)函數(shù)就不能再帶參數(shù)。第四十三頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載如果將一個(gè)重載的運(yùn)算符定義為友元函數(shù),則友元函數(shù)的參數(shù)個(gè)數(shù)和實(shí)際參數(shù)個(gè)數(shù)相同成員函數(shù)與友元函數(shù)的相同點(diǎn): 二者都可以訪問類的私有成員和保護(hù)成員第四十四頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

二元運(yùn)算符的重載(以“+”為例)定義①作為類的成員函數(shù),具有一個(gè)參數(shù)

classCOUNTER { public: intoperator+(COUNTER&c); };②作為友元函數(shù),應(yīng)有兩個(gè)參數(shù)

classCOUNTER { public: friendintoperator+(COUNTER&c1,COUNTER&c2); };

第四十五頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載函數(shù)實(shí)現(xiàn)①成員函數(shù)的實(shí)現(xiàn)

intCOUNTER::operator+(COUNTER&c) { returnvalue+c.value; }②友元函數(shù)的實(shí)現(xiàn)

intoperator+(COUNTER&c1,COUNTER&c2) { returnc1.value+c2.value; }第四十六頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載使用(二者相同)

COUNTERc1(3),c2(4); //創(chuàng)建2個(gè)對(duì)象

cout<<c1+c2; //輸出7

程序中出現(xiàn)的表達(dá)式:

c1+c2

成員函數(shù),編譯程序?qū)⑵浣忉尀椋篶1.operator+(c2)

友元函數(shù),編譯程序?qū)⑵浣忉尀椋簅perator+(c1,c2)第四十七頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

一元運(yùn)算符的重載(以“前綴++”為例)定義——用類成員函數(shù)

classCOUNTER { public:

COUNTER&operator++(); COUNTER(intval){value=val;} //構(gòu)造函數(shù)

intgetvalue(){returnvalue;} private: intvalue; };定義——用友元函數(shù)

classCOUNTER { public:

friendCOUNTER&operator++(COUNTER&c); };類成員函數(shù)默認(rèn)有一個(gè)參數(shù),是調(diào)用該函數(shù)時(shí)所給的對(duì)象本身第四十八頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

函數(shù)實(shí)現(xiàn)類成員函數(shù)的實(shí)現(xiàn)

COUNTER&COUNTER::operator++() { value++; return*this; }友元函數(shù)的實(shí)現(xiàn)

COUNTER&operator++(COUNTER&c) { c.value++;//因?yàn)槭怯言?,所以可以訪問私有成員value returnc; }返回的是當(dāng)前對(duì)象的引用,可以對(duì)當(dāng)前對(duì)象再進(jìn)行運(yùn)算指針?biāo)傅膶?duì)象(當(dāng)前對(duì)象)必須給出哪個(gè)對(duì)象第四十九頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載使用方式

COUNTERc(0); ++c; cout<<c.getvalue(); //輸出1 ++(++c); cout<<c.getvalue(); //輸出3成員函數(shù)與友元函數(shù)的使用方式是相同的注:如果不是用引用返回類型,則不能有上述操作和結(jié)果成員函數(shù):c.operator++()友元函數(shù):operator++(c)第五十頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載賦值運(yùn)算符的重載

//函數(shù)實(shí)現(xiàn)

COUNTER&COUNTER&::operator=(COUNTER&c) { value=c.value; return*this; }

//使用

COUNTERc1(2),c2(5); c1=c2; //對(duì)象的賦值,調(diào)用賦值運(yùn)算符重載函數(shù)注:用對(duì)象初始化對(duì)象調(diào)用拷貝構(gòu)造函數(shù),如:COUNTERc1=c2;

當(dāng)前對(duì)象可作為左值第五十一頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載二元運(yùn)算符與一元運(yùn)算符

成員函數(shù) 友元函數(shù)

二元1個(gè)參數(shù)(實(shí)際還是2個(gè))2個(gè)參數(shù) 一元0個(gè)參數(shù)(實(shí)際還是1個(gè))1個(gè)參數(shù)注:類對(duì)象本身(this)自動(dòng)作為其成員函數(shù)的第一個(gè)參數(shù)第五十二頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

小結(jié)

1.重載運(yùn)算符,可以是類的成員函數(shù)、友元函數(shù)或 普通函數(shù)(普通函數(shù)不常用)

2.二者比較: 參數(shù)的個(gè)數(shù)不同 訪問成員的方式不同 使用方式相同第五十三頁,共九十四頁,編輯于2023年,星期五§8.4運(yùn)算符重載

3.重載的運(yùn)算符可以重新定義的有:

4.重載的運(yùn)算符不能重新定義的有:參數(shù)類型返回值類型參數(shù)個(gè)數(shù)優(yōu)先級(jí)結(jié)合性新的運(yùn)算符第五十四頁,共九十四頁,編輯于2023年,星期五附:總結(jié)幾個(gè)常用概念值返回與引用返回 當(dāng)需要將運(yùn)算結(jié)果作為左值時(shí),用引用返回(見下例)

例:cout<<a<<b;//作為左值,還能再用,就須用引用

++(++a); //如果只用++a,可不用引用返回參數(shù)用引用 參數(shù)用引用,不用復(fù)制對(duì)象副本,可節(jié)省內(nèi)存,提高速度,還可改變參數(shù)的值 例:COUNTER&operator++(COUNTER&c)常量引用參數(shù) 不希望在函數(shù)中改變引用參數(shù)的值 例:intCOUNTER::operator+(constCOUNTER&c) {returnvalue+c.value;}//不希望改變參數(shù)c的值第五十五頁,共九十四頁,編輯于2023年,星期五附:函數(shù)的返回類型是引用舉例//例:求兩個(gè)數(shù)中的最小數(shù)#include<iostream.h>int&min(int&i,int&j){ if(i<=j) returni; else returnj;}voidmain(){ inta=3,b=4; cout<<"a="<<a<<''<<"b="<<b<<endl; min(a,b)=5; cout<<"a="<<a<<''<<"b="<<b<<endl; min(a,b)=0; cout<<"a="<<a<<''<<"b="<<b<<endl;}程序執(zhí)行結(jié)果:

a=3b=4a=5b=4a=5b=0說明:函數(shù)的返回值是引用類型,表示該函數(shù)的返回值是一個(gè)變量的別名,可將函數(shù)調(diào)用作為一個(gè)變量使用,可為其賦值第五十六頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)虛函數(shù)的定義 在類的成員函數(shù)原型前加“virtual”

(該成員函數(shù)稱為虛函數(shù))

如:classA { public:

virtualvoidfun();//fun()是虛函數(shù)

//…… };注:虛函數(shù)必須是類的成員函數(shù)第五十七頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

介紹兩個(gè)與虛函數(shù)有關(guān)的概念函數(shù)的重定義指向基類對(duì)象的指針可以指向派生類對(duì)象第五十八頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)函數(shù)的重定義(overriding) 函數(shù)的原型相同,函數(shù)的實(shí)現(xiàn)不同函數(shù)的重定義與函數(shù)重載的比較 相同點(diǎn):函數(shù)名相同(對(duì)同名函數(shù)進(jìn)行再定義)

不同點(diǎn):1、重定義的函數(shù)只能是類的成員函數(shù),而 重載的函數(shù)則即可對(duì)類成員函數(shù)重載, 也可對(duì)普通函數(shù)重載

2、重定義的函數(shù)原型相同,而重載的函數(shù) 是函數(shù)名相同,參數(shù)不同第五十九頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)重定義函數(shù)的使用 在基類中定義的某成員函數(shù)為虛函數(shù),在其派生類中可以重定義該虛函數(shù)例:classA { public: virtualintarea(intx,inty); //…… }; classB:publicA { public: virtualintarea(intx,inty); //…… };注:函數(shù)體不同,否則使用繼承就可以了第六十頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)指向基類的指針可以指向派生類對(duì)象(downcasting) 指向基類對(duì)象的指針指向派生類后,可以訪問派生類對(duì)象的繼承成員(但不能訪問派生成員)基類派生類如:BASE*pobj;DERIVEDdobj;pobj=&dobj; //基類對(duì)象的指針可以指向派生類第六十一頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)downcasting帶來的問題

classBASE { //…… intfun(); }; classDERIVED:publicBASE { //…… intfun(); };如果:pobj->fun();

//調(diào)用哪個(gè)類的函數(shù)?如果是靜態(tài)綁定,就應(yīng)調(diào)用BASE類的fun(),因?yàn)閜obj是指向BASE類對(duì)象的指針,但現(xiàn)在pobj實(shí)際指向DERIVED類的對(duì)象,所以從道理上應(yīng)調(diào)用DERIVED類的fun(),因此造成二者的矛盾第六十二頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)解決的辦法——virtual函數(shù)

classBASE { //…… virtualintfun(); }; classDERIVED:publicBASE { //…… intfun(); };

BASE*pobj;DERIVEDdobj;pobj=&dobj;

pobj->fun();

//根據(jù)pobj當(dāng)前所指的對(duì)象正確調(diào)用相應(yīng)函數(shù)第六十三頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)虛函數(shù)的含義

1、是一個(gè)類的成員函數(shù)

2、可以為派生類對(duì)象使用

3、派生類可以通過編寫自己的成員函數(shù)來替 代基類的虛函數(shù),這種替代是基類預(yù)見到 的,默認(rèn)的,甚至是贊成的第六十四頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)虛函數(shù)舉例學(xué)生(Student)本科生

(UnderGrad)研究生

(PostGrad)碩士研究生

(MasterGrad)博士研究生

(DoctorGrad)第六十五頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

classSTUDENT { public: virtualvoidSeleteCourse(); //選課

virtualintCalcuCridit(); //計(jì)算總學(xué)分

//…… protected: charname[30]; intage; //…… };

在定義STUDENT類時(shí),已經(jīng)預(yù)見到不同的學(xué)生選課的方式是不一樣的,計(jì)算學(xué)分的方法也不一樣定義成virtual后,就允許派生類根據(jù)自己的需要重新定義成員函數(shù)第六十六頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)//UnderGrad本科生類沒有重新實(shí)現(xiàn)兩個(gè)虛函數(shù),它是用基類的實(shí)現(xiàn)

classUNDERGRAD:publicSTUDENT { public: voidpractice(); //工程實(shí)踐

private: …… };本科生使用基類的兩個(gè)虛函數(shù)(基類中必須有兩個(gè)虛函數(shù)的實(shí)現(xiàn))第六十七頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)//PostGrad研究生類重新實(shí)現(xiàn)兩個(gè)虛函數(shù)

classPOSTGRAD:publicSTUDENT { public: virtualvoidSeleteCourse(); //選課

virtualintCalcuCridit(); //計(jì)算總學(xué)分

private: intSupervisorID; //導(dǎo)師

//…… };第六十八頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)//MasterGrad碩士生使用PostGrad提供的虛函數(shù)

classMASTERGRAD:publicPOSTGRAD { public: //…… }第六十九頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)//DoctorGrad博士生類重新實(shí)現(xiàn)兩個(gè)虛函數(shù)

classDOCTORGRAD:publicPOSTGRAD { public:

voidSeleteCourse(); //選課

intCalcuCridit(); //計(jì)算總學(xué)分

//……

};第七十頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)虛函數(shù)的好處

在基類中提供了一個(gè)接口,都用同樣的調(diào)用方式。具體派生類如何實(shí)現(xiàn),可由派生類去決定,既可以使用基類的實(shí)現(xiàn),也可以不使用基類的實(shí)現(xiàn),派生類定義自己的實(shí)現(xiàn)第七十一頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

voidmain() { STUDENT*s; //s可能指向以下各種派生類對(duì)象

//程序運(yùn)行過程中動(dòng)態(tài)創(chuàng)建學(xué)生對(duì)象,可能是以下各種語句

//s=newUNDERGRAD(); //s=newPOSTGRAD(); //s=newDOCTORGRAD(); //s=newMASTERGRAD(); S->SeleteCourse(); //調(diào)用POSTGRAD::SeleteCourse()因?yàn)?/p>

MASTERGRAD類中沒有實(shí)現(xiàn)函數(shù),調(diào) 用它的直接基類POSTGRAD中的函數(shù)

//…… }第七十二頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

virtual的含義virtual只在類繼承時(shí)才發(fā)輝作用virtual告訴編譯器,它所修飾的函數(shù)需要?jiǎng)討B(tài)綁定在調(diào)用該函數(shù)時(shí),需要根據(jù)對(duì)象的實(shí)際類型決定使用類繼承層次中的哪個(gè)類的成員函數(shù) (是哪個(gè)類的對(duì)象就調(diào)用哪個(gè)類的成員函數(shù))第七十三頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)使用虛函數(shù)的例子

//students存放所有學(xué)生的信息

STUDENT*students[3000]; //指針數(shù)組

intStudNum; //學(xué)生數(shù)目

//在程序運(yùn)行過程中動(dòng)態(tài)創(chuàng)建了StudNum個(gè)學(xué)生對(duì)象

//students[StudNum++]=newDoctorGrad(); //students[StudNum++]=newUnderGrad(); //……

第七十四頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

//所有學(xué)生選課

voidStudentSeleteCourse() { for(inti=0;i<StudNum;i++) students[i]->SeleteCourse(); //…… } //程序非常簡單學(xué)生本科生研究生碩士生博士生復(fù)雜的實(shí)現(xiàn)虛函數(shù)第七十五頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)如果不用虛函數(shù),則程序會(huì)非常復(fù)雜voidStudentSeleteCourse(){ for(inti=0;i<StudNum;i++) switch(students[i]->type) { caseGRAD: //本科生

students[i]->UNDERGRAD::SeleteCourse(); break; casePOST: //研究生

students[i]->POSTGRAD::SeleteCourse(); break; caseDOCT: //博士生

//…… } //……不僅麻煩,若再加一種學(xué)生還需修改程序,如果用虛函 數(shù)就不用作任何改變,只加一個(gè)派生類….

第七十六頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

虛函數(shù)的好處:多態(tài)性 主要體現(xiàn)在如下方面:程序簡單設(shè)計(jì)與實(shí)現(xiàn)分開,實(shí)現(xiàn)了一定的封裝

在基類中設(shè)計(jì)高層邏輯、接口,具體實(shí)現(xiàn)細(xì)節(jié)由派生類根據(jù)各自需要實(shí)現(xiàn),基類可以不用擔(dān)心實(shí)現(xiàn)細(xì)節(jié)程序可重用,易擴(kuò)充

如:加一種學(xué)生,只需加一個(gè)派生類的虛函數(shù)實(shí)現(xiàn)多態(tài)性語言的實(shí)現(xiàn) 體現(xiàn)“同一接口,多種方法”的多態(tài)性概念第七十七頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)虛函數(shù)的缺點(diǎn):增加運(yùn)行開銷(多占用內(nèi)存空間)每個(gè)對(duì)象增加一個(gè)指針調(diào)用虛函數(shù)時(shí)要查表

虛函數(shù)的內(nèi)部實(shí)現(xiàn)

STUDENT::SeleteCoursePOSTGRAD::SeleteCourseDOCTORGRAD::SeleteCourseMASTERGRAD::SeleteCourse……V-table虛擬表(所有虛函數(shù)都在此表中)nameage….V-pointer學(xué)生對(duì)象所有對(duì)象都有一個(gè)指針如果沒有虛函數(shù),則對(duì)象沒有這個(gè)特殊成員第七十八頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

使用虛函數(shù)的注意事項(xiàng)派生類中重新定義基類中的虛成員函數(shù),必須在函數(shù)原型上與基類中的虛成員函數(shù)保持一致派生類對(duì)象調(diào)用虛函數(shù)時(shí),如果該虛函數(shù)在派生類中重新定義了,則執(zhí)行派生類所定義的操作,否則執(zhí)行基類中所定義的操作基類中的非虛函數(shù)不能在派生類中重新(覆蓋)定義派生類中的虛函數(shù),virtual關(guān)鍵字可有可無,如果下一級(jí)派生類還需要使用時(shí),則必須有virtual調(diào)用虛函數(shù)操作的是指向?qū)ο蟮闹羔樆驅(qū)ο笠?(調(diào)用虛函數(shù)的參數(shù)只能是對(duì)象指針或?qū)ο笠茫┑谄呤彭摚簿攀捻?,編輯?023年,星期五§8.5虛函數(shù)

例:虛函數(shù)

#include<iostream.h> classPOINT { public: POINT(intx1,inty1) {x=x1;y=y1;} virtualintarea() {return0;} private: intx,y; };第八十頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)classRECT:publicPOINT{ public: RECT(intx1,inty1,intl1,intw1):POINT(x1,y1) { l=l1;w=w1; } intarea() //虛函數(shù)

{ returnl*w; } private: intl,w;};第八十一頁,共九十四頁,編輯于2023年,星期五§8.5虛函數(shù)

voidfun(POINT&p) { cout<<p.area()<<endl; } voidmain() { RECTrec(2,4,10,6); fun(rec); }

程序執(zhí)行結(jié)果:60說明:1、fun函數(shù)的引用對(duì)象參數(shù)p被動(dòng)態(tài)綁定,該函數(shù)體內(nèi)調(diào)用的area()在運(yùn)行中被確定為RECT類中的area函數(shù)2、該程序中如果沒有virtual關(guān)鍵字,則為靜態(tài)綁定,輸出結(jié)果為0第八十二頁,共九十四頁,編輯于2023年,星期五§8.6純虛函數(shù)與抽象類純虛函數(shù) 是一種特殊的虛函數(shù)純虛函數(shù)的定義格式 在基類的虛函數(shù)原型的分號(hào)前加“=0”

例:classPOINT { public: virtualintarea()=0; //…… };第八十三頁,共九十四頁,編輯于2023年,星期五§8.6純虛函數(shù)與抽象類 純虛函數(shù)的特點(diǎn)純虛函數(shù)是將要被派生類實(shí)現(xiàn)的函數(shù)

(純虛函數(shù)只有函數(shù)原型,沒有函數(shù)實(shí)現(xiàn))具有純虛函數(shù)的類不能實(shí)例化(不能創(chuàng)建對(duì)象,因?yàn)檫@種類不完整)派生類中如果還有純虛函數(shù),則還不能實(shí)例化,能實(shí)例化的派生類必須實(shí)現(xiàn)所有純虛函數(shù)第八十四頁,共九十四頁,編輯于2023年,星期五§8.6純虛函數(shù)與抽象類

純虛函數(shù)的作用為抽象基類的定義提供了手段為所有派生類設(shè)計(jì)一個(gè)標(biāo)準(zhǔn)接口,方便高層應(yīng)用邏輯的設(shè)計(jì)第八十五頁,共九十四頁,編輯于2023年,星期五§8.6純虛函數(shù)與抽象類例:學(xué)生選課

classABSTRACT_STUDENT { public: virtualvoidSeleteCourse()=0; virtualintCalcuCridit()=0; //…… protected: charname[30]; intage; //…… };

純虛函數(shù)沒有實(shí)現(xiàn),只有

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論