老師課件描述_第1頁
老師課件描述_第2頁
老師課件描述_第3頁
老師課件描述_第4頁
老師課件描述_第5頁
已閱讀5頁,還剩58頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

面向?qū)ο蟪绦蛟O(shè)計(jì)(C++)第7章多態(tài)北京理工大學(xué)信息與電子學(xué)院白霞bai@本章主要內(nèi)容繼承呼喚多態(tài)虛函數(shù)純虛函數(shù)與抽象類7.1

繼承呼喚多態(tài)class

Studentclass

GraduateStudent

:

public

StudentGraduateStudent

gs;gsStudent部分GraduateStudent部分父子互易的說明(賦值兼容規(guī)則)gssGraduateStudent

gs;Student

s=gs;派生類的對象可以賦值給基類對象父子互易的說明(賦值兼容規(guī)則)gsspsGraduateStudent

gs;Student

s=gs;Student

*ps=&gs;派生類的對象可以賦值給基類對象派生類對象地址可以賦值給基類指針gs=s;GraduateStudent

*pgs=&s;?類家族類家族:同一個繼承層次結(jié)構(gòu)中所有相關(guān)的類在一條繼承線上發(fā)展的類家族從一個父親派生出多個類的類家族一個簡單規(guī)則指向基類的指針可以指向派生類的對象基類指針可以指向派生類對象,然而它所能支配的成員依然只有基類部分的成員同化效應(yīng){

cout<<"Student\n";

}};class

GraduateStudent

:public

Student{public:void

display(){ cout<<"Graduate

Student\n";

}};void

main(){Student

s;GraduateStudent

gs;s.display();gs.display();}#include

<iostream.h>對象操作,則

class

Student{public:void

display()對于右邊的類和結(jié)果為:StudentStudent若執(zhí)行s

=

gs;則執(zhí)行

s.display();結(jié)果為:Graduate

Studentgs雖然是研究生對象,但在賦值給大學(xué)生對象操作之后,被大學(xué)生同化了,喪失了研究生的本性.同化效應(yīng)蔓延到指針{public:void

display(){

cout<<"Student\n";

}};class

GraduateStudent

:public

Student{public:void

display(){ cout<<"Graduate

Student\n";

}};void

main(){

Student

s,*ps;GraduateStudent

gs;ps=&s;ps->display();ps=&gs;ps->display();}結(jié)果為:sgspsStudentStudentgs雖然是Gra#dinucluadtee<Siotsutredaemn.ht>對象,但是對于右邊的類和對托象付操給作,了則Stucdlaesns

St之tude后nt

,便一切都表現(xiàn)為Student渴望多態(tài)學(xué)校設(shè)立一個繳費(fèi)辦公室,處理學(xué)生的繳費(fèi)工作。};class

GraduateStudent:

public

Student{

public:void

calTuition();void

display();};int

main()ps[i]->calTuition();ps[i]->display();return

0;}alTuition()ee2=800;

fee3=400;e2+fee3;splay()#include

<iostream.h>

void

Student::class

Student

{

fee1=4200{

public:

fee=fee1+fvoid

calTuition();

}void

display();

void

Student::protected:

{ cout<<“大double

fee,fee1,fee2,fee3; cout<<"學(xué)cout<<"住宿cout<<"總費(fèi)生收費(fèi)"<<endl;:"<<fee1<<endl;費(fèi):"<<fee2<<endl;:"<<fee3<<endl;用:"<<fee<<endl;}void

GraduateStudent::calTuition(){ fee1=0;

fee2=1800;

fee3=400;fee=fee2+fee3;GraduateStudent

gs;

void

GraduateStudent::display()cout<<"住宿費(fèi):"<<fee2<<endl;cout<<"其 他:"<<fee3<<endl;cout<<"總費(fèi)用:"<<fee<<endl;}c

大學(xué)生收費(fèi);

f

學(xué) 費(fèi):4200e

住宿費(fèi):800其 他:400di

總費(fèi)用:5400學(xué)大學(xué)生收費(fèi)費(fèi)學(xué)費(fèi):4200住宿費(fèi):800cout<<"其 他

其他:400總費(fèi)用:5400{

Student

因s;

為同化效應(yīng)的原因,}

函數(shù)Student

只*ps[能2]=體{&s現(xiàn),&g大s}

學(xué)生的操作{

c,ou不t<<“研究生收費(fèi)"<<endl;for(int

i=能0;i<處2;++理i)

研究生的情況我們希望一個集合中允許有類家族的不同類的對象的共存,對每個元素的操作具有分辨不同類對象的能力!多態(tài)現(xiàn)實(shí)中的上課鈴:不同班級的學(xué)生回到了不同的教室多態(tài)性是面向?qū)ο蟮闹匾匦?,是指不同對?/p>

收到相同的消息時產(chǎn)生不同的行為。消息是指

調(diào)用類的成員函數(shù),不同的行為指不同的實(shí)現(xiàn),即調(diào)用不同的函數(shù);兩種多態(tài)性:1、編譯時的多態(tài)性2、運(yùn)行時的多態(tài)性多態(tài)性程序中的同名函數(shù):依賴每個對象自己做出恰當(dāng)?shù)捻憫?yīng)C++支持兩種多態(tài)性編譯時的多態(tài)是在程序編譯過程中確定函數(shù)操作的具體對象,通過函數(shù)重載來實(shí)現(xiàn);運(yùn)行時的多態(tài)是在程序運(yùn)行過程中才能確定函數(shù)操作的具體對象,通過虛函數(shù)來實(shí)現(xiàn)。靜態(tài)聯(lián)編和動態(tài)聯(lián)編聯(lián)了編解:函是數(shù)指執(zhí)一行個所程需序自要身檢彼測此的關(guān)信聯(lián)息的,過它程對。函按數(shù)照的聯(lián)編所選進(jìn)擇行是的基階于段指不向同對,可象分的為指靜針態(tài)的聯(lián)類編型和動態(tài)聯(lián)編。靜態(tài)聯(lián)編:在程序編譯階段將函數(shù)實(shí)現(xiàn)和函數(shù)調(diào)用關(guān)聯(lián)起來稱之為靜態(tài)聯(lián)編對成員函數(shù)的選擇不是基于指針類型,而是基于所指向的對象的類型動態(tài)聯(lián)編:在程序執(zhí)行階段將函數(shù)實(shí)現(xiàn)和函數(shù)調(diào)用關(guān)聯(lián)起來稱之為動態(tài)聯(lián)編7.2

虛函數(shù)虛函數(shù)提供了OOP方法的動態(tài)聯(lián)編體系聲明函數(shù)名前面插入virtualvirtual

說明函數(shù)的原型,不必用在函數(shù)實(shí)現(xiàn)具有繼承性,基類中聲明虛函數(shù),派生類中無論是否說明,同原型函數(shù)都自動為虛函數(shù)在派生類中重新定義虛函數(shù),要求函數(shù)原型必須與基類中的原型完全一致調(diào)用通過基類指針,執(zhí)行時會根據(jù)指針指向的對象的類,決定調(diào)用哪個函數(shù)虛函數(shù)#include

<iostream.h>class

Student{

public:void

calTuition();void

display();protected:double

fee,

fee1,fee2,fee3;};class

GraduateStudent:

public

Student{

public:void

calTuition();void

display();};int

main(){

Student

s;GraduateStudent

gs;Student

*ps[2]={&s,&gs}for(int

i=0;i<2;++i)ps[i]->calTuition();ps[i]->display();return

0;}void

Student::calTuition(){ fee1=4200;

fee2=800;

fee3=400;fee=fee1+fee2+fee3;}void

Student::display(){ cout<<"大學(xué)生收費(fèi)"<<endl;cout<<"學(xué) 費(fèi):"<<fee1<<endl;cout<<"住宿費(fèi):"<<fee2<<endl;cout<<"其 他:"<<fee3<<endl;cout<<"總費(fèi)用:"<<fee<<endl;}void

GraduateStudent::calTuition(){ fee1=0;

fee2=1800;

fee3=400;fee=fee2+fee3;}void

GraduateStudent::display(){ cout<<“研究生收費(fèi)"<<endl;cout<<"住宿費(fèi):"<<fee2<<endl;cout<<"其 他:"<<fee3<<endl;cout<<"總費(fèi)用:"<<fee<<endl;}

virtual

void

calTuition();virtual

void

display();#include

<iostream.h>class

Student{

public:

virtual

void

calTuition();

virtual

void

display();protected:double

fee,

fee1,fee2,fee3;};class

GraduateStudent:

public

Student{

public:void

calTuition();void

display();};int

main(){

Student

s;GraduateStudent

gs;Student

*ps[2]={&s,&gs}for(int

i=0;i<2;++i)

ps[i]->calTuition();

ps[i]->display();

return

0;}{

fee1=420fee=fee1+}calTuition()0;

fee2=800;

fee3=400;fee2+fee3;display(){cout<<"大cout<<"學(xué)cout<<"住cout<<"其學(xué)生收費(fèi)"<<endl;費(fèi):"<<fee1<<endl;宿費(fèi):"<<fee2<<endl;他:"<<fee3<<endl;cout<<"總費(fèi)用:"<<fee<<endl;}void

GraduateStudent::calTuition(){ fee1=0;

fee2=1800;

fee3=400;}void

GraduateStudent::display(){ cout<<“研究生收費(fèi)"<<endl;cout<<"住宿費(fèi):"<<fee2<<endl;cout<<"其 他:"<<fee3<<endl;cout<<"總費(fèi)用:"<<fee<<endl;}void

Student::

大學(xué)生收費(fèi)學(xué) 費(fèi):4200住宿費(fèi):800其 他:400void

Student::

總費(fèi)用:5400研究生收費(fèi)住宿費(fèi):1800其 他:400總費(fèi)用:2200同化效應(yīng)如何被fe破e=fe解e2?+fee3;聽到了上課鈴,不同班級的學(xué)生回到了不同的教室,為什么?class

GraduateStudent:

public

Student{

public:void

calTuition();void

display();};Student::calTuition()Student::display()vtable(*calTuition)()(*display)()vptrfeefee1fee2fee3(*calTuition)()(*display)()GraduateStudent::calTuition()GraduateStudent::display()vtablevptrfeeclass

Student{

public:virtual

void

calTuition();virtual

void

display();fee1fee2fee3protected:double

fee,

fee1,fee2,fee3;};

虛函數(shù)表的實(shí)現(xiàn)原理有得必有失額外的內(nèi)存:如果基類中有虛函數(shù),編譯器會自動為每個由該基類及其派生類所定義的對象加上一個叫v-pointer的指針,簡稱vptr調(diào)用效率要低:編譯器還為每個類加上了一個叫做virtualtable的表,簡稱vtable。函數(shù)調(diào)用使用了間接的函數(shù)調(diào)用表方法不要將那些不需要在派生類中重新定義的基類成員函數(shù)聲明為虛函數(shù)觸發(fā)動態(tài)聯(lián)編的兩個條件第一:成員函數(shù)指定為虛函數(shù)調(diào)用虛函數(shù),一定是動態(tài)聯(lián)編么?第二:必須通過基類類型的指針或引用進(jìn)行函數(shù)調(diào)用例9.2.1基類指針指向不同對象,執(zhí)行不同對象對應(yīng)的類的成員函數(shù)虛析構(gòu)函數(shù)如果派生類層次中包含析構(gòu)函數(shù),那么把基類的析構(gòu)函數(shù)定義為虛函數(shù)若基類的析構(gòu)函數(shù)聲明為虛函數(shù),則由該基類派生的所有派生類的析構(gòu)函數(shù)也都自動成為虛函數(shù),即使派生類的析構(gòu)函數(shù)與基類的析構(gòu)函數(shù)不同名虛析構(gòu)函數(shù)的作用保證使用操作符delete時能夠調(diào)用正確的析構(gòu)函數(shù)#include

<iostream.h>class

A{public:~A

(){cout<<“A::~A()

called.\n“;};};class

B:

public

A{public:~B

(){cout<<“B::~B()

called.\n“;};};int

main(){A*

prt=new

B;delete

prt;return

0;}virtual

~A

(){cout<<“A::~A()

called.\n“;};返回類型的例外如果父類和子類的同名成員函數(shù)參數(shù)格式相同,父類和子類的成員函數(shù)返回自己的對象指針或引用,仍然實(shí)現(xiàn)多態(tài)#include

<iostream.h>class

Base{public:virtual

Base*

afn(){

cout<<“In

Base

class\n";

}};class

Sub:public

Base{public:Sub*

afn(){ cout<<“In

Sub

class\n";

}};void

test(Base&

x){Base

*b;b=x.afn();}void

main(){

test(Base());test(Sub());}編譯器認(rèn)為

Base*

afn();Sub*afn();是同型的In

Base

classIn

Sub

class虛函數(shù)使用注意在同一個類家族中,希望一個指針能指向不同的類,那么把它定義為指向基類定義了指向類家族中對象的指針,且不同類中有同名函數(shù)時,使用虛函數(shù)定義基類的析構(gòu)函數(shù)為虛函數(shù),可以保證派生類被正確析構(gòu)虛函數(shù)使用注意(續(xù))成員函數(shù)才能聲明為虛函數(shù)構(gòu)造函數(shù)不能是虛函數(shù)類家族的存在對象尚未建立內(nèi)聯(lián)函數(shù)不能是虛函數(shù)內(nèi)聯(lián)是代碼展開,不是地址5.3

純虛函數(shù)與抽象類如果基類的虛函數(shù)中沒有任何代碼,那么這個虛函數(shù)稱作“純虛函數(shù)”virtualtype

函數(shù)名(參數(shù)表)=0;純虛函數(shù)的存在使派生類僅僅只是繼承函數(shù)的接口(普通虛函數(shù)使派生類繼承函數(shù)的接口和缺省實(shí)現(xiàn))純虛函數(shù)的聲明就象是在告訴子類的設(shè)計(jì)者,"你必須提供一個函數(shù),但我不知道你會怎樣實(shí)現(xiàn)它。"抽象類包含純虛函數(shù)的基類稱作抽象類,因?yàn)樗浅橄蟮?,只是為派生類提供一個模式,不會實(shí)例化產(chǎn)生對象virtual

type

函數(shù)名(參數(shù)表)=0;表明該函數(shù)在本類定義中已經(jīng)終結(jié),不再有其實(shí)現(xiàn)作為抽象類的標(biāo)志編寫一個程序,計(jì)算正方體和球體的表面積和體積注意:純虛函數(shù)只有函數(shù)的名字,不具備函數(shù)功能,不能被調(diào)用如果在派生類中沒有定義純虛函數(shù)的版本,則該虛函數(shù)在派生類中仍然是純虛函數(shù)抽象類不能建立對象#include

<iostream.h>//定義基類class

Shape{public:virtual

float

area

(

)

=

0;virtual

void

Disp(

)

=

0;//定義純虛函數(shù)//定義純虛函數(shù)};class

Rectangle:public

Shape

//定義圖形的派生類矩形類{public:float

area(

);void

Disp(

);//可以定義//可以定義};Shape

*ps

=

new

Shape;Shape

*ps1

=

new

Rectangle;ps1->area();ps1->Disp();//錯誤!Shape是抽象的//正確//調(diào)用Rectangle::area//調(diào)用Rectangle::Disp重載、覆蓋與隱藏重載成員函數(shù)被重載的特征:相同的范圍(在同一個類中)函數(shù)名字相同參數(shù)不同與virtual無關(guān)重載函數(shù)的區(qū)分方式是名字(Name-Mangling)壓延把重載函數(shù)的本名和參數(shù)的數(shù)據(jù)結(jié)合起來,創(chuàng)造函數(shù)的新名字用如下語句調(diào)用ans1=myAns(14.2,25);ans2=myAns(62,’x’);int

myAnsFLAOTINT(flaot

x,

int

i);int

myAnsINTCHAR(int

i,

char

c);例如有如下兩個函數(shù)原型int

myAns(float

x,

int

j);int

myAns(int

i,char

c);ans1=myAnsFLAOTINT(14,2,25);ans2=myAnsINTCHAR(62,’x’);class

Cube{

public:Cube(

)

{

height=1;

width=1;

length=1;}Cube(int

h,int

w,int

l);

{

height=h;

width=w;

length=l;

}private:int

height;int

width;int

length;};void

main(

){Cube

cube1;Cube

cube2(4,5,6);}Cube()CubeIntIntInt(4,5,6)覆蓋覆蓋是指派生類函數(shù)覆蓋基類函數(shù),特征是:不同的范圍(分別位于派生類與基類)函數(shù)名字相同參數(shù)相同基類函數(shù)必須有virtual

關(guān)鍵字覆蓋規(guī)則其實(shí)就是C++虛函數(shù)表的實(shí)現(xiàn)原理虛函數(shù)表一個虛擬函數(shù)地址表,稱為vtable。每個類的

vtable中記錄的是所有聲明為virtual的成員函數(shù)的地址如果在派生類中沒有覆蓋基類的成員函數(shù),則在vtable中記錄的是基類成員函數(shù)的地址如果在派生類中有覆蓋到基類的成員函數(shù),則在vtable中記錄的是派生類成員函數(shù)的地址class

base{public:func();virtual

vfunc1();virtual

vfunc2();virtual

vfunc3();private:int

_data1;int

_data2;};class

derived:

public

base{public:vfunc2();};void

main(

){Derived

d;Base

*pb

=

&d;pb->vfunc2();}vptr

--------->

(*vfunc1)()

----------->

base::vfunc1();_data1_data2(*vfunc2)()

----------->

base::vfunc2();(*vfunc3)()

----------->

base::vfunc3();derived對象實(shí)例

vtablevptr

--------->

(*vfunc1)()

----------->

base::vfunc1()_data1;_data2;(*vfunc2)()

----------->

derived::vfunc2()(*vfunc3)()

----------->

base::vfunc3()如果基類中有虛函數(shù),編譯器會自動為每個由該基類及其派生類所定義的對象加上一個叫v-pointer的base指對針象,實(shí)簡例稱vptr。vtable編譯器還為每個類加上了一個叫做vtable的表vptr指向vtable開頭的地方A對象實(shí)例

vtablevptr

--------->

溫馨提示

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

評論

0/150

提交評論