版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第7章多態(tài)性
2011年10月12日主要內(nèi)容多態(tài)性的實(shí)現(xiàn)類型聯(lián)編虛函數(shù)抽象類函數(shù)重載運(yùn)算符重載7.1多態(tài)性的實(shí)現(xiàn)類型多態(tài)性就是向不同的對象發(fā)送同一個(gè)消息,不同的對象在接收時(shí)會(huì)產(chǎn)生不同的行為。面向?qū)ο蟮亩鄳B(tài)性分為四類:
7.2聯(lián)編多態(tài)性的實(shí)現(xiàn)過程中,確定調(diào)用哪一個(gè)同名函數(shù)的過程就是聯(lián)編,又稱為綁定。按照聯(lián)編進(jìn)行的階段不同,可以分為靜態(tài)聯(lián)編和動(dòng)態(tài)聯(lián)編,這兩種聯(lián)編分別對應(yīng)C++面向?qū)ο蠹夹g(shù)多態(tài)特性的兩種實(shí)現(xiàn)方式。7.2.1靜態(tài)聯(lián)編
靜態(tài)聯(lián)編是指在編譯階段完成的聯(lián)編方式。在編譯過程中,編譯系統(tǒng)可以根據(jù)參數(shù)類型和參數(shù)數(shù)量的不同來確定調(diào)用哪一個(gè)同名函數(shù)。其特點(diǎn)是函數(shù)調(diào)用速度快、效率高,不足之處是編程不夠靈活。例7-1.靜態(tài)聯(lián)編使用#include<iostream>usingnamespacestd;classUndergraduate{public: voidDisplay(){
cout<<"CallBaseClass"<<endl;
cout<<"UndergraduateLiMing"<<endl; }};classMaster:publicUndergraduate{public: voidDisplay(){
cout<<"CallMasterClass"<<endl;
cout<<"MasterWangWei"<<endl; }};classDoctor:publicMaster{
public:
voidDisplay(){
cout<<"CallDoctorClass"<<endl;
cout<<"DoctorZhangHua"<<endl;
}
};
voidmain(){
Undergraduates1,*pointer;//定義基類對象s1和指向基類的指針
Masters2;//定義派生類對象s2
Doctors3;//定義派生類對象s3
pointer=&s1;//指針pointer指向基類對象s1
pointer->Display();
pointer=&s2;//指針pointer指向基類對象s2
//期望調(diào)用對象s2的函數(shù)display,但實(shí)際執(zhí)行卻調(diào)用了對象s1的輸出函數(shù)
pointer->Display();
pointer=&s3;
//期望調(diào)用對象s3的函數(shù)display,但實(shí)際執(zhí)行卻調(diào)用了對象s1的輸出函數(shù)
pointer->Display();
}程序運(yùn)行結(jié)果
CallBaseClassUndergraduateLiMingCallBaseClassUndergraduateLiMingCallBaseClassUndergraduateLiMing7.2.2動(dòng)態(tài)聯(lián)編只有在程序運(yùn)行時(shí)才能確定將要調(diào)用哪一個(gè)函數(shù)。動(dòng)態(tài)聯(lián)編的主要優(yōu)點(diǎn)是使編程更具靈活性,對問題的抽象更方便,程序的易維護(hù)性更好;其缺點(diǎn)是與靜態(tài)聯(lián)編相比,函數(shù)調(diào)用速度更慢。在編譯階段不能解決的聯(lián)編問題,需要等到程序運(yùn)行以后才能確定,則選擇動(dòng)態(tài)聯(lián)編,這就需要虛函數(shù)來解決7.3虛函數(shù)虛函數(shù)是動(dòng)態(tài)聯(lián)編的主要實(shí)現(xiàn)方式,是動(dòng)態(tài)聯(lián)編的基礎(chǔ)。虛函數(shù)的作用是允許在派生類中重新定義與基類同名的函數(shù),并且可以通過基類指針或引用來訪問基類和派生類中的同名函數(shù),聲明方式是:virtual返回值類型函數(shù)名(參數(shù)表){
函數(shù)體;}7.3.1虛函數(shù)的使用(1)在基類聲明成員函數(shù)為虛函數(shù),在類外定義虛函數(shù)是不必再加virtual。(2)在派生類中重新定義此函數(shù)時(shí),要求函數(shù)名、函數(shù)類型、參數(shù)個(gè)數(shù)和參數(shù)類型全部與虛函數(shù)相同,否者會(huì)被認(rèn)為是普通的函數(shù)重載。并根據(jù)需要重新定義函數(shù)體。C++規(guī)定當(dāng)一個(gè)成員函數(shù)被定義成虛函數(shù)后,其派生類中的同名函數(shù)都自動(dòng)成為虛函數(shù),故virtual也可不加,但為了提高可讀性,最好都加上。(3)定義一個(gè)指向基類對象的指針變量,并使它指向同一類族中的某一對象。
(4)通過該指針調(diào)用此虛函數(shù),此時(shí)調(diào)用的就是指針變量指向的對象的同名函數(shù)。例7-2.通過對象引用調(diào)用虛函數(shù)實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編
#include<iostream.h>classUndergraduate{public: virtualvoidprint(){
cout<<"CallBaseClass"<<endl;
cout<<"UndergraduateLiMing"<<endl; }};classMaster:publicUndergraduate{public: virtualvoidprint(){
cout<<"CallMaterClass"<<endl;
cout<<"MasterWangWei"<<endl; }};
voidfunction(Undergraduate&s){
s.print();//通過對象引用調(diào)用虛函數(shù)
}
voidmain(){
Undergraduates1;
Masters2;
function(s1);
function(s2);
}
程序運(yùn)行結(jié)果:CallBaseClassUndergraduateLiMingCallMaterClassMasterWangWei應(yīng)當(dāng)聲明虛函數(shù)的情況:(1)首先成員函數(shù)所在的類必須會(huì)作為基類,然后看成員函數(shù)在類的繼承之后有無可能被更改功能,如果希望更改其功能的,一般將其聲明為虛函數(shù),若不更改,則不需聲明虛函數(shù)。(2)考慮對成員函數(shù)的調(diào)用是通過對象名還是通過基類指針或引用,如果是通過基類指針或引用去訪問的,則應(yīng)當(dāng)聲明為虛函數(shù)。(3)有時(shí)定義虛函數(shù)時(shí),函數(shù)體是空的,其功能留給派生類去增加。7.3.2虛析構(gòu)函數(shù)如果用new運(yùn)算符建立了臨時(shí)對象,若基類中有析構(gòu)函數(shù),并且定了了一個(gè)指向該基類的指針變量。在程序用帶指針參數(shù)的delete運(yùn)算符撤銷對象是會(huì)發(fā)生一個(gè)情況:系統(tǒng)只會(huì)執(zhí)行基類的析構(gòu)函數(shù),而不執(zhí)行派生類的析構(gòu)函數(shù)。為解決此問題,可將基類的析構(gòu)函數(shù)聲明為虛函數(shù)
virtual~類名(){
函數(shù)體
}7.4純虛函數(shù)和抽象類純虛函數(shù)是在聲明虛函數(shù)時(shí)被“初始化”為0的函數(shù),一般形式為Virtual函數(shù)類型函數(shù)名(參數(shù)表)=0;不用來定義對象而只作為一種基本類型用作繼承的類,稱為抽象類。由于它常用作基類,通常稱為抽象基類。凡是包含純虛函數(shù)的類都是抽象類。例7-3使用純虛函數(shù)
#include<iostream.h>classpoint{
public:
point(inti=0,intj=0){x0=i;y0=j;}
virtualvoidset()=0;
virtualvoiddraw()=0;
protected:
intx0,y0;};classline:publicpoint{
public:
line(inti=0,intj=0,intm=0,intn=0):point(i,j){
x1=m;y1=n;
}
voidset(){cout<<"line::set()called.\n";}
voiddraw(){cout<<"line::draw()called.\n";}
protected:
intx1,y1;
};
classellipse:publicpoint{
public:
ellipse(inti=0,intj=0,intp=0,intq=0):point(i,j){
x2=p;y2=q;
}
voidset(){cout<<"ellipse::set()called.\n";}
voiddraw(){cout<<"ellipse::draw()called.\n";}
protected:
intx2,y2;
};
voiddrawobj(point*p){
p->draw();
}
voidsetobj(point*p){
p->set();
}
voidmain(){
line*lineobj=newline;
ellipse*elliobj=newellipse;
drawobj(lineobj);
drawobj(elliobj);
cout<<endl;
setobj(lineobj);
setobj(elliobj);
cout<<"\nRedrawtheobject…\n";
drawobj(lineobj);
drawobj(elliobj);
}
程序運(yùn)行結(jié)果line::draw()called.ellipse::draw()called.
line::set()called.ellipse::set()called.
Redrawtheobject…line::draw()called.ellipse::draw()called.
綜上所述,可將純虛函數(shù)歸結(jié)為:抽象類的唯一用途是為派生類提供基類,純虛函數(shù)的作用是作為派生類的成員函數(shù)的基礎(chǔ),并實(shí)現(xiàn)動(dòng)態(tài)多態(tài)性。7.5函數(shù)重載函數(shù)重載是指兩個(gè)或兩個(gè)以上的函數(shù)具有相同的函數(shù)名,但參數(shù)類型不一致或參數(shù)個(gè)數(shù)不同,從而使重載的函數(shù)雖然函數(shù)名相同,但功能上卻不完全相同。函數(shù)重載包括成員函數(shù)的重載和普通函數(shù)的重載。例7-4構(gòu)造函數(shù)進(jìn)行重載#include<iostream.h>#include<string.h>classstring{
public:
string(char*s);
string(string&s1);
string(intsize=80);
~string(){deletesptr;}
int
getlen(){returnlength;}
voidprint(){cout<<sptr<<endl;}
private:
char*sptr;
intlength;};string::string(char*s){length=strlen(s);
sptr=newchar[length+1];
strcpy(sptr,s);}string::string(string&s1){length=s1.length;
sptr=newchar[length+1];
strcpy(sptr,s1.sptr);}string::string(intsize){length=size;
sptr=newchar[length+1];*sptr='\0';}voidmain(){stringstr1("Thisisastring.");str1.print();
cout<<str1.getlen()<<endl;char*s1="Thatisaprogram.";stringstr2(s1);stringstr3(str2);str3.print();
cout<<str3.getlen()<<endl;}運(yùn)行結(jié)果:Thisisastring.17Thatisaprogram.187.6運(yùn)算符重載運(yùn)算符重載是對已有的運(yùn)算符賦予多重含義必要性C++中預(yù)定義的運(yùn)算符其運(yùn)算對象只能是基本數(shù)據(jù)類型,而不適用于用戶自定義類型(如類)實(shí)現(xiàn)機(jī)制將指定的運(yùn)算表達(dá)式轉(zhuǎn)化為對運(yùn)算符函數(shù)的調(diào)用,運(yùn)算對象轉(zhuǎn)化為運(yùn)算符函數(shù)的實(shí)參。編譯系統(tǒng)對重載運(yùn)算符的選擇,遵循函數(shù)重載的選擇原則。7.6.1運(yùn)算符重載規(guī)則可以重載C++中除下列運(yùn)算符外的所有運(yùn)算符:
.*->::sizeof?:只能重載C++語言中已有的運(yùn)算符,不可臆造新的。不改變原運(yùn)算符的優(yōu)先級和結(jié)合性。不能改變操作數(shù)個(gè)數(shù)。經(jīng)重載的運(yùn)算符,其操作數(shù)中至少應(yīng)該有一個(gè)是自定義類型。運(yùn)算符重載的兩種方式重載為類的成員函數(shù)重載為類的友元函數(shù)7.6.2運(yùn)算符重載為成員函數(shù)聲明形式返回值類型operator運(yùn)算符(形參){
函數(shù)體}重載為類成員函數(shù)時(shí)
參數(shù)個(gè)數(shù)=原操作數(shù)個(gè)數(shù)-1 (后置++、--除外)運(yùn)算符成員函數(shù)的設(shè)計(jì)雙目運(yùn)算符B如果要重載B為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達(dá)式oprd1Boprd2,其中
oprd1為A類對象,則B應(yīng)被重載為A類的成員函數(shù),形參類型應(yīng)該是oprd2
所屬的類型。經(jīng)重載后,表達(dá)式
oprd1Boprd2
相當(dāng)于oprd1.operatorB(oprd2)例7-5
將“+”、“-”運(yùn)算重載為復(fù)數(shù)類的成員函數(shù)。規(guī)則:實(shí)部和虛部分別相加減。操作數(shù):兩個(gè)操作數(shù)都是復(fù)數(shù)類的對象。#include<iostream>usingnamespacestd;classcomplex //復(fù)數(shù)類聲明{public: //外部接口
complex(doubler=0.0,doublei=0.0){real=r;imag=i;}//構(gòu)造函數(shù)
complexoperator+(complexc2);//+重載為成員函數(shù)
complexoperator-(complexc2);//-重載為成員函數(shù)
voiddisplay(); //輸出復(fù)數(shù)private: doublereal; //復(fù)數(shù)實(shí)部
doubleimag; //復(fù)數(shù)虛部}; complexcomplex::operator+(complexc2)//重載函數(shù)實(shí)現(xiàn){ complexc;
c.real=c2.real+real;
c.imag=c2.imag+imag; returncomplex(c.real,c.imag);}complexcomplex::operator-(complexc2)//重載函數(shù)實(shí)現(xiàn){ complexc;
c.real=real-c2.real;
c.imag=imag-c2.imag; returncomplex(c.real,c.imag);}voidcomplex::display(){cout<<"("<<real<<","<<imag<<")"<<endl;}voidmain()//主函數(shù){ complexc1(5,4),c2(2,10),c3;//聲明復(fù)數(shù)類的對象
cout<<"c1=";c1.display();
cout<<"c2=";c2.display();
c3=c1-c2; //使用重載運(yùn)算符完成復(fù)數(shù)減法
cout<<"c3=c1-c2="; c3.display();
c3=c1+c2; //使用重載運(yùn)算符完成復(fù)數(shù)加法
cout<<"c3=c1+c2="; c3.display();}程序輸出的結(jié)果為:c1=(5,4)c2=(2,10)c3=c1-c2=(3,-6)c3=c1+c2=(7,14)運(yùn)算符成員函數(shù)的設(shè)計(jì)前置單目運(yùn)算符U如果要重載U為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達(dá)式Uoprd,其中
oprd
為A類對象,則U應(yīng)被重載為A類的成員函數(shù),無形參。經(jīng)重載后,
表達(dá)式
Uoprd
相當(dāng)于oprd.operatorU()后置單目運(yùn)算符++和--如果要重載++或--為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達(dá)式
oprd++
或oprd--
,其中
oprd
為A類對象,則++或--應(yīng)被重載為A類的成員函數(shù),且具有一個(gè)int
類型形參。經(jīng)重載后,表達(dá)式
oprd++
相當(dāng)于oprd.operator++(0)例7-6運(yùn)算符前置++和后置++重載為時(shí)鐘類的成員函數(shù)。前置單目運(yùn)算符,重載函數(shù)沒有形參,對于后置單目運(yùn)算符,重載函數(shù)需要有一個(gè)整型形參。操作數(shù)是時(shí)鐘類的對象。實(shí)現(xiàn)時(shí)間增加1秒鐘。#include<iostream>usingnamespacestd;classClock //時(shí)鐘類聲明{public: //外部接口
Clock(int
NewH=0,int
NewM=0,int
NewS=0){ Hour=NewH; Minute=NewM; Second=NewS; } voidShowTime(){cout<<Hour<<":"<<Minute<<":"<<Second<<endl;} Clock&operator++();//前置單目運(yùn)算符重載
Clockoperator
++(int);//后置單目運(yùn)算符重載
private: //私有數(shù)據(jù)成員
int
Hour,Minute,Second;};Clock&Clock::operator++() //前置單目運(yùn)算符重載函數(shù){ Second++;
if(Second>=60) {Second=Second-60; Minute++;
if(Minute>=60) { Minute=Minute-60; Hour++; Hour=Hour%24; } }return*this;}ClockClock::operator++(int) //后置單目運(yùn)算符重載{ Clockold=*this;++(*this);
returnold;}voidmain(){ ClockmyClock(23,59,59);
cout<<"Firsttimeoutput:";
myClock.ShowTime();
cout<<"ShowmyClock++:"
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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ǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年開發(fā)商與購房者長租公寓買賣合同范本3篇
- 二零二五年度餐飲服務(wù)業(yè)勞動(dòng)合同模板及食品安全3篇
- 二零二五版特種動(dòng)物繁育與購銷一體化服務(wù)合同3篇
- 二零二五年教育機(jī)構(gòu)教學(xué)資源整合合同書3篇
- 二零二五年空壓機(jī)租賃與應(yīng)急響應(yīng)服務(wù)合同3篇
- 二零二五年教育培訓(xùn)機(jī)構(gòu)代理招生合同模板3篇
- 二零二五版未成年人撫養(yǎng)權(quán)變更合同3篇
- 二零二五年度財(cái)務(wù)風(fēng)險(xiǎn)控制合同3篇
- 二零二五年度鋼材采購與智能制造合作合同3篇
- 二零二五版豪華游輪包船旅游運(yùn)輸服務(wù)合同參考模板2篇
- 2024版?zhèn)€人私有房屋購買合同
- 2025年山東光明電力服務(wù)公司招聘筆試參考題庫含答案解析
- 《神經(jīng)發(fā)展障礙 兒童社交溝通障礙康復(fù)規(guī)范》
- 2025年中建六局二級子企業(yè)總經(jīng)理崗位公開招聘高頻重點(diǎn)提升(共500題)附帶答案詳解
- 2024年5月江蘇省事業(yè)單位招聘考試【綜合知識與能力素質(zhì)】真題及答案解析(管理類和其他類)
- 注漿工安全技術(shù)措施
- 2024年世界職業(yè)院校技能大賽“食品安全與質(zhì)量檢測組”參考試題庫(含答案)
- 3-9年級信息技術(shù)(人教版、清華版)教科書資源下載
- 上海牛津版三年級英語3B期末試卷及答案(共5頁)
- 行為疼痛量表BPS
- 小學(xué)生必背古詩詞80首(硬筆書法田字格)
評論
0/150
提交評論