版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第7章多態(tài)性
2011年10月12日主要內(nèi)容多態(tài)性的實現(xiàn)類型聯(lián)編虛函數(shù)抽象類函數(shù)重載運算符重載7.1多態(tài)性的實現(xiàn)類型多態(tài)性就是向不同的對象發(fā)送同一個消息,不同的對象在接收時會產(chǎn)生不同的行為。面向?qū)ο蟮亩鄳B(tài)性分為四類:
7.2聯(lián)編多態(tài)性的實現(xiàn)過程中,確定調(diào)用哪一個同名函數(shù)的過程就是聯(lián)編,又稱為綁定。按照聯(lián)編進行的階段不同,可以分為靜態(tài)聯(lián)編和動態(tài)聯(lián)編,這兩種聯(lián)編分別對應(yīng)C++面向?qū)ο蠹夹g(shù)多態(tài)特性的兩種實現(xiàn)方式。7.2.1靜態(tài)聯(lián)編
靜態(tài)聯(lián)編是指在編譯階段完成的聯(lián)編方式。在編譯過程中,編譯系統(tǒng)可以根據(jù)參數(shù)類型和參數(shù)數(shù)量的不同來確定調(diào)用哪一個同名函數(shù)。其特點是函數(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,但實際執(zhí)行卻調(diào)用了對象s1的輸出函數(shù)
pointer->Display();
pointer=&s3;
//期望調(diào)用對象s3的函數(shù)display,但實際執(zhí)行卻調(diào)用了對象s1的輸出函數(shù)
pointer->Display();
}程序運行結(jié)果
CallBaseClassUndergraduateLiMingCallBaseClassUndergraduateLiMingCallBaseClassUndergraduateLiMing7.2.2動態(tài)聯(lián)編只有在程序運行時才能確定將要調(diào)用哪一個函數(shù)。動態(tài)聯(lián)編的主要優(yōu)點是使編程更具靈活性,對問題的抽象更方便,程序的易維護性更好;其缺點是與靜態(tài)聯(lián)編相比,函數(shù)調(diào)用速度更慢。在編譯階段不能解決的聯(lián)編問題,需要等到程序運行以后才能確定,則選擇動態(tài)聯(lián)編,這就需要虛函數(shù)來解決7.3虛函數(shù)虛函數(shù)是動態(tài)聯(lián)編的主要實現(xiàn)方式,是動態(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ù)和參數(shù)類型全部與虛函數(shù)相同,否者會被認為是普通的函數(shù)重載。并根據(jù)需要重新定義函數(shù)體。C++規(guī)定當一個成員函數(shù)被定義成虛函數(shù)后,其派生類中的同名函數(shù)都自動成為虛函數(shù),故virtual也可不加,但為了提高可讀性,最好都加上。(3)定義一個指向基類對象的指針變量,并使它指向同一類族中的某一對象。
(4)通過該指針調(diào)用此虛函數(shù),此時調(diào)用的就是指針變量指向的對象的同名函數(shù)。例7-2.通過對象引用調(diào)用虛函數(shù)實現(xiàn)動態(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);
}
程序運行結(jié)果:CallBaseClassUndergraduateLiMingCallMaterClassMasterWangWei應(yīng)當聲明虛函數(shù)的情況:(1)首先成員函數(shù)所在的類必須會作為基類,然后看成員函數(shù)在類的繼承之后有無可能被更改功能,如果希望更改其功能的,一般將其聲明為虛函數(shù),若不更改,則不需聲明虛函數(shù)。(2)考慮對成員函數(shù)的調(diào)用是通過對象名還是通過基類指針或引用,如果是通過基類指針或引用去訪問的,則應(yīng)當聲明為虛函數(shù)。(3)有時定義虛函數(shù)時,函數(shù)體是空的,其功能留給派生類去增加。7.3.2虛析構(gòu)函數(shù)如果用new運算符建立了臨時對象,若基類中有析構(gòu)函數(shù),并且定了了一個指向該基類的指針變量。在程序用帶指針參數(shù)的delete運算符撤銷對象是會發(fā)生一個情況:系統(tǒng)只會執(zhí)行基類的析構(gòu)函數(shù),而不執(zhí)行派生類的析構(gòu)函數(shù)。為解決此問題,可將基類的析構(gòu)函數(shù)聲明為虛函數(shù)
virtual~類名(){
函數(shù)體
}7.4純虛函數(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);
}
程序運行結(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ǔ),并實現(xiàn)動態(tài)多態(tài)性。7.5函數(shù)重載函數(shù)重載是指兩個或兩個以上的函數(shù)具有相同的函數(shù)名,但參數(shù)類型不一致或參數(shù)個數(shù)不同,從而使重載的函數(shù)雖然函數(shù)名相同,但功能上卻不完全相同。函數(shù)重載包括成員函數(shù)的重載和普通函數(shù)的重載。例7-4構(gòu)造函數(shù)進行重載#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;}運行結(jié)果:Thisisastring.17Thatisaprogram.187.6運算符重載運算符重載是對已有的運算符賦予多重含義必要性C++中預(yù)定義的運算符其運算對象只能是基本數(shù)據(jù)類型,而不適用于用戶自定義類型(如類)實現(xiàn)機制將指定的運算表達式轉(zhuǎn)化為對運算符函數(shù)的調(diào)用,運算對象轉(zhuǎn)化為運算符函數(shù)的實參。編譯系統(tǒng)對重載運算符的選擇,遵循函數(shù)重載的選擇原則。7.6.1運算符重載規(guī)則可以重載C++中除下列運算符外的所有運算符:
.*->::sizeof?:只能重載C++語言中已有的運算符,不可臆造新的。不改變原運算符的優(yōu)先級和結(jié)合性。不能改變操作數(shù)個數(shù)。經(jīng)重載的運算符,其操作數(shù)中至少應(yīng)該有一個是自定義類型。運算符重載的兩種方式重載為類的成員函數(shù)重載為類的友元函數(shù)7.6.2運算符重載為成員函數(shù)聲明形式返回值類型operator運算符(形參){
函數(shù)體}重載為類成員函數(shù)時
參數(shù)個數(shù)=原操作數(shù)個數(shù)-1 (后置++、--除外)運算符成員函數(shù)的設(shè)計雙目運算符B如果要重載B為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達式oprd1Boprd2,其中
oprd1為A類對象,則B應(yīng)被重載為A類的成員函數(shù),形參類型應(yīng)該是oprd2
所屬的類型。經(jīng)重載后,表達式
oprd1Boprd2
相當于oprd1.operatorB(oprd2)例7-5
將“+”、“-”運算重載為復(fù)數(shù)類的成員函數(shù)。規(guī)則:實部和虛部分別相加減。操作數(shù):兩個操作數(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ù)實部
doubleimag; //復(fù)數(shù)虛部}; complexcomplex::operator+(complexc2)//重載函數(shù)實現(xiàn){ complexc;
c.real=c2.real+real;
c.imag=c2.imag+imag; returncomplex(c.real,c.imag);}complexcomplex::operator-(complexc2)//重載函數(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; //使用重載運算符完成復(fù)數(shù)減法
cout<<"c3=c1-c2="; c3.display();
c3=c1+c2; //使用重載運算符完成復(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)運算符成員函數(shù)的設(shè)計前置單目運算符U如果要重載U為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達式Uoprd,其中
oprd
為A類對象,則U應(yīng)被重載為A類的成員函數(shù),無形參。經(jīng)重載后,
表達式
Uoprd
相當于oprd.operatorU()后置單目運算符++和--如果要重載++或--為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達式
oprd++
或oprd--
,其中
oprd
為A類對象,則++或--應(yīng)被重載為A類的成員函數(shù),且具有一個int
類型形參。經(jīng)重載后,表達式
oprd++
相當于oprd.operator++(0)例7-6運算符前置++和后置++重載為時鐘類的成員函數(shù)。前置單目運算符,重載函數(shù)沒有形參,對于后置單目運算符,重載函數(shù)需要有一個整型形參。操作數(shù)是時鐘類的對象。實現(xiàn)時間增加1秒鐘。#include<iostream>usingnamespacestd;classClock //時鐘類聲明{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++();//前置單目運算符重載
Clockoperator
++(int);//后置單目運算符重載
private: //私有數(shù)據(jù)成員
int
Hour,Minute,Second;};Clock&Clock::operator++() //前置單目運算符重載函數(shù){ Second++;
if(Second>=60) {Second=Second-60; Minute++;
if(Minute>=60) { Minute=Minute-60; Hour++; Hour=Hour%24; } }return*this;}ClockClock::operator++(int) //后置單目運算符重載{ 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)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度美團外賣外賣配送區(qū)域劃分及優(yōu)化合同4篇
- 二零二五年度生物醫(yī)藥研發(fā)平臺土地租賃合同3篇
- 2025年巡演設(shè)備租賃合同
- 2025年度個人消費貸款合同提前還款流程規(guī)范4篇
- 2025年度特色農(nóng)產(chǎn)品加工廠舊房購置合同書4篇
- 2025年家電預(yù)付款服務(wù)合同
- 二零二五年度池塘租賃合同(含水產(chǎn)養(yǎng)殖技術(shù)培訓合作)4篇
- 2025年河南許昌市建安區(qū)國有公司招聘筆試參考題庫含答案解析
- 2025年冀教新版八年級歷史上冊月考試卷含答案
- 2025年江蘇句容新農(nóng)控股集團公司招聘筆試參考題庫含答案解析
- 廣東省茂名市電白區(qū)2024-2025學年七年級上學期期末質(zhì)量監(jiān)測生物學試卷(含答案)
- 2024版?zhèn)€人私有房屋購買合同
- 2024爆炸物運輸安全保障協(xié)議版B版
- 2025年度軍人軍事秘密保護保密協(xié)議與信息安全風險評估合同3篇
- 《食品與食品》課件
- 讀書分享會《白夜行》
- 光伏工程施工組織設(shè)計
- DB4101-T 121-2024 類家庭社會工作服務(wù)規(guī)范
- 化學纖維的鑒別與測試方法考核試卷
- 2024-2025學年全國中學生天文知識競賽考試題庫(含答案)
- 自動駕駛汽車道路交通安全性探討研究論文
評論
0/150
提交評論