《計(jì)算機(jī)網(wǎng)絡(luò)原理》第8章-多態(tài)性和虛函數(shù)-精選課件_第1頁(yè)
《計(jì)算機(jī)網(wǎng)絡(luò)原理》第8章-多態(tài)性和虛函數(shù)-精選課件_第2頁(yè)
《計(jì)算機(jī)網(wǎng)絡(luò)原理》第8章-多態(tài)性和虛函數(shù)-精選課件_第3頁(yè)
《計(jì)算機(jī)網(wǎng)絡(luò)原理》第8章-多態(tài)性和虛函數(shù)-精選課件_第4頁(yè)
《計(jì)算機(jī)網(wǎng)絡(luò)原理》第8章-多態(tài)性和虛函數(shù)-精選課件_第5頁(yè)
已閱讀5頁(yè),還剩31頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

C++支持兩種多態(tài)性,即編譯時(shí)的多態(tài)性和運(yùn)行時(shí)的多態(tài)性。編譯時(shí)的多態(tài)性通過(guò)使用重載函數(shù)或模板獲得,運(yùn)行時(shí)的多態(tài)性通過(guò)使用繼承和虛函數(shù)來(lái)獲得。聯(lián)編是描述編譯器決定在程序運(yùn)行時(shí),一個(gè)函數(shù)調(diào)用應(yīng)執(zhí)行哪段代碼的一個(gè)術(shù)語(yǔ),是實(shí)現(xiàn)多態(tài)性的基礎(chǔ)。第8章多態(tài)性和虛函數(shù)第8章多態(tài)性和虛函數(shù)28.1多態(tài)性8.1.1靜態(tài)聯(lián)編中的賦值兼容性和名字支配規(guī)律類(lèi)的對(duì)象和調(diào)用的函數(shù)一一對(duì)應(yīng),程序編譯時(shí)即可確定對(duì)象調(diào)用哪一個(gè)函數(shù),稱(chēng)為靜態(tài)聯(lián)編通過(guò)指針調(diào)用成員函數(shù)時(shí):所調(diào)用成員函數(shù)為指針?biāo)鶎兕?lèi)的成員函數(shù)即由賦值兼容規(guī)則決定指針調(diào)用的成員函數(shù)348.1.2動(dòng)態(tài)聯(lián)編的多態(tài)性要實(shí)現(xiàn)程序運(yùn)行時(shí)決定指針?biāo){(diào)用的函數(shù)是基類(lèi)的還是派生類(lèi)的,即:動(dòng)態(tài)聯(lián)編??衫锰摵瘮?shù)實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編

由此可見(jiàn),對(duì)象的內(nèi)存地址空間中只包含數(shù)據(jù)成員,并不存儲(chǔ)有關(guān)成員函數(shù)的信息。這些成員函數(shù)的地址翻譯過(guò)程與其對(duì)象的內(nèi)存地址無(wú)關(guān)。編譯器只根據(jù)數(shù)據(jù)類(lèi)型翻譯成員函數(shù)的地址并判斷調(diào)用的合法性。virtualdoublearea(){return0.0;}

當(dāng)編譯系統(tǒng)編譯含有虛函數(shù)的類(lèi)時(shí),為它建立一個(gè)虛函數(shù)表,表中的每一個(gè)元素都指向一個(gè)虛函數(shù)的地址。此外,編譯器也為類(lèi)增加一個(gè)數(shù)據(jù)成員,這個(gè)數(shù)據(jù)成員是一個(gè)指向該虛函數(shù)表的指針,通常稱(chēng)為vptr。如果派生類(lèi)Circle沒(méi)有重寫(xiě)這個(gè)area虛函數(shù),則派生類(lèi)的虛函數(shù)表里的元素所指向的地址就是基類(lèi)Point的虛函數(shù)area的地址,即派生類(lèi)僅繼承基類(lèi)的虛函數(shù),它調(diào)用的也是基類(lèi)的area函數(shù)。現(xiàn)在將它改寫(xiě)如下:virtualdoublearea(){returnPI*radius*radius;}這時(shí),編譯器也將派生類(lèi)虛函數(shù)表里的元素指向Circle::area(),即指向派生類(lèi)area函數(shù)的地址。

由此可見(jiàn),虛函數(shù)的地址翻譯取決于對(duì)象的內(nèi)存地址。編譯器為含有虛函數(shù)類(lèi)的對(duì)象首先建立一個(gè)入口地址,這個(gè)地址用來(lái)存放指向虛函數(shù)表的指針vptr,然后按照類(lèi)中虛函數(shù)的聲明次序,一一填入函數(shù)指針。當(dāng)調(diào)用虛函數(shù)時(shí),先通過(guò)vptr找到虛函數(shù)表,然后再找出虛函數(shù)的真正地址。派生類(lèi)能繼承基類(lèi)的虛函數(shù)表,而且只要是和基類(lèi)同名的(參數(shù)也相同)成員函數(shù),無(wú)論是否使用virtual聲明,它們都自動(dòng)成為虛函數(shù)。如果派生類(lèi)沒(méi)有改寫(xiě)繼承基類(lèi)的虛函數(shù),則函數(shù)指針調(diào)用基類(lèi)的虛函數(shù)。如果派生類(lèi)改寫(xiě)了基類(lèi)的虛函數(shù),編譯器將重新為派生類(lèi)的虛函數(shù)建立地址,則函數(shù)指針調(diào)用這個(gè)改寫(xiě)過(guò)的虛函數(shù)。98.2虛函數(shù)8.2.1虛函數(shù)的定義虛函數(shù)的格式:

virtualdoublearea(){return0;}虛函數(shù)的調(diào)用規(guī)則:根據(jù)當(dāng)前對(duì)象,優(yōu)先調(diào)用對(duì)象本身的虛成員函數(shù)。虛函數(shù)是動(dòng)態(tài)聯(lián)編的,是在執(zhí)行期間接調(diào)用實(shí)際上欲聯(lián)編的函數(shù)。一旦基類(lèi)定義了虛函數(shù),該基類(lèi)的派生類(lèi)中的同名函數(shù)也自動(dòng)成為虛函數(shù)。虛函數(shù)不能是靜態(tài)成員。108.2.

2虛函數(shù)實(shí)現(xiàn)多態(tài)性使用虛函數(shù)產(chǎn)生多態(tài)的3個(gè)前提:1、類(lèi)之間的繼承關(guān)系滿(mǎn)足賦值兼容性規(guī)則;2、改寫(xiě)了同名虛函數(shù);3、根據(jù)賦值兼容性規(guī)則使用指針(或引用)。其中前提3分為兩種情況:1、按賦值兼容性規(guī)則使用基類(lèi)指針(或引用)訪(fǎng)問(wèn)虛函數(shù);2、把指針(或引用)作為函數(shù)參數(shù),即這個(gè)函數(shù)不一定是類(lèi)的成員函數(shù),可以是普通函數(shù),而且可以重載?!綪171中的display函數(shù)】【例8.2】分別使用指針和引用的display函數(shù)。分析下面程序的輸出結(jié)果:#include<iostream>usingnamespacestd;constdoublePI=3.14159;classPoint{private:doublex,y;public:Point(doublei,doublej){x=i;y=j;} virtualdoublearea(){return0;}};classCircle:publicPoint{private:doubleradius;public: Circle(doublea,doubleb,doubler):Point(a,b) {radius=r;}doublearea(){returnPI*radius*radius;}};voiddisplay(Point*p){cout<<p->area()<<endl;}voiddisplay(Point&a){cout<<a.area()<<endl;}voidmain(){Pointa(1.5,6.7);Circlec(1.5,6.7,2.5);Point*p=&c;Point&rc=c;display(a);display(p);//display(&c)display(rc);//display(c)}程序輸出如下:019.634919.6349148.2.3構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用虛函數(shù)重要規(guī)則:采用靜態(tài)聯(lián)編,即只調(diào)用自己的類(lèi)或基類(lèi)中定義的函數(shù),但不是任何在派生類(lèi)中重定義的虛函數(shù)。P83new和構(gòu)造函數(shù)delete和析構(gòu)函數(shù)標(biāo)準(zhǔn)c++不支持虛構(gòu)造函數(shù)支持虛析構(gòu)函數(shù),如果基類(lèi)的虛析構(gòu)函數(shù),則派生類(lèi)的析構(gòu)函數(shù)是否用virtual說(shuō)明,均為虛析構(gòu)函數(shù);如派生類(lèi)未定義析構(gòu)函數(shù),則編譯器生成的也是虛析構(gòu)函數(shù)。

在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛函數(shù)時(shí),采用靜態(tài)聯(lián)編,即它們所調(diào)用的虛函數(shù)是自己的類(lèi)或基類(lèi)中定義的函數(shù),但不是任何在派生類(lèi)中重定義的虛函數(shù)?!纠?.3】在構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用虛函數(shù)。

#include<iostream>usingnamespacestd;classA{public:A(){}virtualvoidfunc(){cout<<"ConstructingA"<<endl;}~A(){}virtualvoidfund(){cout<<"DestructorA"<<endl;}};classB:publicA{public:B(){func();}voidfun(){cout<<"Comehereandgo...";func();}~B(){fund();}};classC:publicB{public:C(){}voidfunc(){cout<<"ClassC"<<endl;}~C(){fund();}voidfund(){cout<<"DestructorC"<<endl;}};

voidmain(){Cc;c.fun();}輸出結(jié)果如下:ConstructingA//建立對(duì)象c調(diào)用B()產(chǎn)生Comehereandgo...ClassC//c.fun()輸出DestructorC//析構(gòu)對(duì)象c時(shí),由~C()產(chǎn)生DestructorA//析構(gòu)對(duì)象c時(shí)調(diào)用~B()產(chǎn)生析構(gòu)時(shí)應(yīng)先調(diào)用C的析構(gòu)函數(shù),輸出“DestructorC”。接著調(diào)用類(lèi)B的析構(gòu)函數(shù),這個(gè)析構(gòu)函數(shù)調(diào)用虛函數(shù)fund。這個(gè)虛函數(shù)分別在類(lèi)B的基類(lèi)A和派生類(lèi)C中定義,它只能調(diào)用它的基類(lèi)中的虛函數(shù)fund,輸出“DestructorA”。基類(lèi)A中的析構(gòu)函數(shù)沒(méi)有輸出信息,程序結(jié)束運(yùn)行。目前推薦的C++標(biāo)準(zhǔn)不支持虛構(gòu)造函數(shù)。由于析構(gòu)函數(shù)不允許有參數(shù),因此一個(gè)類(lèi)只能有一個(gè)虛析構(gòu)函數(shù)。虛析構(gòu)函數(shù)使用virtual說(shuō)明。只要基類(lèi)的析構(gòu)函數(shù)被說(shuō)明為虛函數(shù),則派生類(lèi)的析構(gòu)函數(shù),無(wú)論是否使用virtual進(jìn)行說(shuō)明,都自動(dòng)地成為虛函數(shù)。delete運(yùn)算符和析構(gòu)函數(shù)一起工作(new和構(gòu)造函數(shù)一起工作),當(dāng)使用delete刪除一個(gè)對(duì)象時(shí),delete隱含著對(duì)析構(gòu)函數(shù)的一次調(diào)用,如果析構(gòu)函數(shù)為虛函數(shù),則這個(gè)調(diào)用采用動(dòng)態(tài)聯(lián)編。一般說(shuō)來(lái),如果一個(gè)類(lèi)中定義了虛函數(shù),析構(gòu)函數(shù)也應(yīng)說(shuō)明為虛函數(shù),尤其是在析構(gòu)函數(shù)要完成一些有意義的任務(wù)時(shí),例如釋放內(nèi)存等。如果基類(lèi)的析構(gòu)函數(shù)為虛函數(shù),則在派生類(lèi)未定義析構(gòu)函數(shù)時(shí),編譯器所生成的析構(gòu)函數(shù)也為虛函數(shù)。19

可以在基類(lèi)Point中加一個(gè)area函數(shù),并聲明為虛函數(shù): virtualfloatarea(){return0;}

其返回值為0,表示“點(diǎn)”是沒(méi)有面積的。其實(shí),在基類(lèi)中并不使用這個(gè)函數(shù),其返回值也是沒(méi)有意義的。為簡(jiǎn)化,只給出函數(shù)的原型,并在后面加上“=0”,如

virtualfloatarea()=0; //純虛函數(shù)

純虛函數(shù):是在聲明虛函數(shù)時(shí)被“初始化”為0的函數(shù)。 聲明純虛函數(shù)的一般形式是:

virtual函數(shù)類(lèi)型函數(shù)名(參數(shù)表列)=0;·8.2.4純虛函數(shù)與抽象類(lèi)20純虛函數(shù)

有時(shí)在基類(lèi)中將某一成員函數(shù)定為虛函數(shù),并不是基類(lèi)本身的要求,而是考慮到派生類(lèi)的需要,在基類(lèi)中預(yù)留了一個(gè)函數(shù)名,具體功能留給派生類(lèi)根據(jù)需要去定義。

如: 基類(lèi)Point中沒(méi)有求面積的area函數(shù);

直接派生類(lèi)Circle中需要有area函數(shù)求圓面積;

間接派生類(lèi)Cylinder中需要有area函數(shù)求圓柱體表面積。8.2.4純虛函數(shù)與抽象類(lèi)218.2.4

純虛函數(shù)與抽象類(lèi)抽象類(lèi)的派生類(lèi)如果沒(méi)有實(shí)現(xiàn)抽象類(lèi)中的全部純虛函數(shù),這個(gè)派生類(lèi)依舊是抽象類(lèi)。純虛函數(shù)與空的虛函數(shù)是不同的:1、virtualvoidarea()=0;2、virtualvoidarea(){}

【例9.5】編寫(xiě)一個(gè)程序,用于計(jì)算正方形、矩形、直角三角形和圓的總面積。classshape{public:virtualdoublearea()=0;//純虛函數(shù)};classsquare:publicshape{protected:doubleH;public:square(doublei){H=i;}doublearea(){returnH*H;}};classcircle:publicsquare{public:circle(doubler):square(r){}doublearea(){returnH*H*3.14159;}};classtriangle:publicsquare{protected:doubleW;public:triangle(doubleh,doublew):square(h){W=w;}doublearea(){returnH*W*0.5;}};classrectangle:publictriangle{public:

rectangle(doubleh,doublew):triangle(h,w){}doublearea(){returnH*W;}};doubletotal(shape*s[],intn){doublesum=0.0;for(inti=0;i<n;i++)sum+=s[i]->area();returnsum;}#include<iostream>usingnamespacestd;voidmain(){

shape*s[5];s[0]=newsquare(4);s[1]=newtriangle(3,6);s[2]=newrectangle(3,6);s[3]=newsquare(6);s[4]=newcircle(10);for(inti=0;i<5;i++)cout<<"s["<<i<<"]="<<s[i]->area()<<endl;doublesum=total(s,5);cout<<"Thetotalareais:"<<sum<<endl;}程序輸出結(jié)果如下:s[0]=16s[1]=9s[2]=18s[3]=36s[4]=314.159Thetotalareais:393.159shape類(lèi)中的虛函數(shù)area僅起到為派生類(lèi)提供一個(gè)一致的接口的作用,派生類(lèi)中重定義的area用于決定以什么樣的方式計(jì)算面積。由于在shape類(lèi)中不能對(duì)此做出決定,因此被說(shuō)明為純虛函數(shù)。由此可見(jiàn),賦值兼容規(guī)則使人們可將正方形、三角形和圓等都視為形狀,多態(tài)性又保證了函數(shù)total在對(duì)各種形狀求面積之和時(shí),無(wú)須關(guān)心當(dāng)前正在計(jì)算哪種具體形狀的面積。在需要時(shí),函數(shù)total可從這些形狀的對(duì)象那里獲得該對(duì)象的面積,成員函數(shù)area保證了這點(diǎn)。

27注意: 1.純虛函數(shù)沒(méi)有函數(shù)體;

2.最后面的“=0”并不表示函數(shù)返回值為0,它只起形式上的作用,告訴編譯系統(tǒng)“這是純虛函數(shù)”;

3.這是一個(gè)聲明語(yǔ)句,最后應(yīng)有分號(hào)。

4.純虛函數(shù)的作用是在基類(lèi)中為其派生類(lèi)保留一個(gè)函數(shù)的名字,以便派生類(lèi)根據(jù)需要對(duì)它進(jìn)行定義。

5.如果在一個(gè)類(lèi)中聲明了純虛函數(shù),而在其派生類(lèi)中沒(méi)有對(duì)該函數(shù)定義,則該虛函數(shù)在派生類(lèi)中仍然為純虛函數(shù)。8.2.4純虛函數(shù)與抽象類(lèi)28抽象類(lèi): 如果聲明了一個(gè)類(lèi),它們不用來(lái)生成對(duì)象。定義這些類(lèi)的惟一目的是用它作為基類(lèi)去建立派生類(lèi)。它們作為一種基本類(lèi)型提供給用戶(hù),用戶(hù)在這個(gè)基礎(chǔ)上根據(jù)自己的需要定義出功能各異的派生類(lèi)。用這些派生類(lèi)去建立對(duì)象。 這種不用來(lái)定義對(duì)象而只作為一種基本類(lèi)型用作繼承的類(lèi),稱(chēng)為抽象類(lèi)(abstractclass),由于它常用作基類(lèi),通常稱(chēng)為抽象基類(lèi)(abstractbaseclass)。8.2.4純虛函數(shù)與抽象類(lèi)29

凡是包含純虛函數(shù)的類(lèi)都是抽象類(lèi)。因?yàn)榧兲摵瘮?shù)是不能被調(diào)用的,包含純虛函數(shù)的類(lèi)是無(wú)法建立對(duì)象的。 抽象類(lèi)的作用是作為一個(gè)類(lèi)族的共同基類(lèi),或者說(shuō),為一個(gè)類(lèi)族提供一個(gè)公共接口。 一個(gè)類(lèi)層次結(jié)構(gòu)中當(dāng)然也可不包含任何抽象類(lèi),每一層次的類(lèi)都是實(shí)際可用的,可以用來(lái)建立對(duì)象的。 但是,許多好的面向?qū)ο蟮南到y(tǒng),其層次結(jié)構(gòu)的頂部是一個(gè)抽象類(lèi),甚至頂部有好幾層都是抽象類(lèi)。8.2.4純虛函數(shù)與抽象類(lèi)30

如果在抽象類(lèi)所派生出的新類(lèi)中對(duì)基類(lèi)的所有純虛函數(shù)進(jìn)行了定義,那么這些函數(shù)就被賦予了功能,可以被調(diào)用,這個(gè)派生類(lèi)就不是抽象類(lèi),可以用來(lái)創(chuàng)建對(duì)象。 如果在派生類(lèi)中沒(méi)有對(duì)所有純虛函數(shù)進(jìn)行定義,則此派生類(lèi)仍然是抽象類(lèi),不能用來(lái)定義對(duì)象。 雖然抽象類(lèi)不能定義對(duì)象(或者說(shuō)抽象類(lèi)不能實(shí)例化),但可以定義指向抽象類(lèi)數(shù)據(jù)的指針變量。當(dāng)派生類(lèi)成為具體類(lèi)之后,就可以用這種指針指向派生類(lèi)對(duì)象,然后通過(guò)該指針調(diào)用虛函數(shù),實(shí)現(xiàn)多態(tài)性的操作。8.2.4純虛函數(shù)與抽象類(lèi)31#include<iostream>usingnamespacestd;classB0//抽象基類(lèi)B0聲明{public://外部接口

virtualvoiddisplay()=0;//純虛函數(shù)成員};classB1:publicB0//公有派生{public: voiddisplay(){cout<<"B1::display()"<<endl;}//虛成員函數(shù)};classD1:publicB1//公有派生{public: voiddisplay(){cout<<"D1::display()"<<endl;}//虛成員函數(shù)};32voidfun(B0*ptr) //普通函數(shù){ ptr->display();}intmain() //主函數(shù){ B0*p; //聲明抽象基類(lèi)指針

B1b1; //聲明派生類(lèi)對(duì)象

D1d1; //聲明派生類(lèi)對(duì)象

p=&b1; fun(p); //調(diào)用派生類(lèi)B1函數(shù)成員

p=&d1; fun(p); //調(diào)用派生類(lèi)D1函數(shù)成員}運(yùn)行結(jié)果:B1::di

溫馨提示

  • 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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論