文庫發(fā)布:c第7章多態(tài)性_第1頁
文庫發(fā)布:c第7章多態(tài)性_第2頁
文庫發(fā)布:c第7章多態(tài)性_第3頁
文庫發(fā)布:c第7章多態(tài)性_第4頁
文庫發(fā)布:c第7章多態(tài)性_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論