貴州大學(xué)計(jì)算機(jī)學(xué)院Visual C++maocpp5_第1頁
貴州大學(xué)計(jì)算機(jī)學(xué)院Visual C++maocpp5_第2頁
貴州大學(xué)計(jì)算機(jī)學(xué)院Visual C++maocpp5_第3頁
貴州大學(xué)計(jì)算機(jī)學(xué)院Visual C++maocpp5_第4頁
貴州大學(xué)計(jì)算機(jī)學(xué)院Visual C++maocpp5_第5頁
已閱讀5頁,還剩128頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第五章多態(tài)性

1

5.1編譯時(shí)的多態(tài)性與運(yùn)行時(shí)的多態(tài)性

多態(tài)性是指用同一個(gè)名字定義不同的函數(shù),這些函數(shù)執(zhí)行不同但

又類似的操作。

聯(lián)編的概念:

一個(gè)源程序經(jīng)過編譯、連接、成為可執(zhí)行文件的過程是把可執(zhí)行

代碼聯(lián)編(或稱裝配)在一起的過程。

靜態(tài)聯(lián)編(前期聯(lián)編)

’靜態(tài)聯(lián)編要求在程序編譯時(shí)就知道調(diào)用哪個(gè)函數(shù),就決定如何

實(shí)現(xiàn)某一動(dòng)作。

動(dòng)態(tài)聯(lián)編(后期聯(lián)編、滯后聯(lián)編)

一直要到程序運(yùn)行時(shí)才能確定調(diào)用哪個(gè)函數(shù)。系統(tǒng)在運(yùn)行時(shí)才動(dòng)

態(tài)完成的聯(lián)編。

靜態(tài)聯(lián)編支持的多態(tài)性稱為編譯時(shí)多態(tài)性,也稱靜態(tài)多態(tài)性。在

C++中,編譯時(shí)多態(tài)性是通過函數(shù)重載和運(yùn)算符重載實(shí)現(xiàn)的。

動(dòng)態(tài)聯(lián)編支持的多態(tài)性稱為運(yùn)行時(shí)多態(tài)性,也稱動(dòng)態(tài)多態(tài)性。在

C++中,運(yùn)行

時(shí)多態(tài)性是通過繼承和虛函數(shù)來實(shí)現(xiàn)的。2

5.2函數(shù)重載I<

質(zhì)譯時(shí)多本件可以通過函數(shù)重載來實(shí)現(xiàn)。函數(shù)重載的意義在于它能

Voidmain()

{pointp(20,20);

circlec(8,8,30);

cout?p.area()?endl;〃執(zhí)彳亍基類point中的area()的函數(shù)

cout?c.area()?endl;〃執(zhí)彳亍派生類circle中的areaO函數(shù)

coutvvc.point::area()vvendl;〃執(zhí)彳亍基類point中的areaO的函數(shù)

}

程序運(yùn)行結(jié)果為:

0

2827.439941

0

classcircle:publicpoint(

intradius;

public:

circle(intx,inty,intrad):point(x,y){radius=rad;}

floatarea(){return34416*radius*radius派生類中Marea函數(shù)

0?3

說明:<

在基類和派生類中的函數(shù)重載有兩種情況:

1.參數(shù)有所差別的重載,這種重載函數(shù)的定義和調(diào)用方法在前面章

節(jié)已進(jìn)行了介紹;在編譯時(shí)根據(jù)參數(shù)不同來區(qū)分函數(shù)重載。

2.函數(shù)所帶的參數(shù)完全相同,只是它們屬于不同的類。這時(shí)要人工

干預(yù),以下兩種方法可以使編譯時(shí)區(qū)別這類函數(shù):

(1)使用對象名加以區(qū)分。例如:p.area()和c.erea()分別

調(diào)用類point的area()函數(shù)和類circle的area()函數(shù)。

(2)使用“類名::''加以區(qū)分。例如:point::area()和

circle::area()分別調(diào)用類point和類circle的area()函數(shù)。

4

5.3運(yùn)算符重載<

在C++中,除了可以對函數(shù)重載外,還可以對大多數(shù)運(yùn)算

符實(shí)施重載。

運(yùn)算符重載通過創(chuàng)建運(yùn)算符函數(shù)operator()來實(shí)現(xiàn)。

運(yùn)算符函數(shù)定義了重載的運(yùn)算符將要進(jìn)行的新的操作,

這種操作通常作用在一個(gè)類上。

函數(shù)operatorO可以

(1)外部函數(shù)

(2)類的友元函數(shù)

(3)是類的成員函數(shù)

5

5.3.1類以外的運(yùn)算符重載<

對基本的數(shù)據(jù)類型,C++提供了許多預(yù)定義的運(yùn)算符,如“+”、”-

工“二,,等,若有一個(gè)復(fù)數(shù)類complex:

classcomplex{

public:

doublereal,imag;

complex(doubler=0,doublei=0){real=r;imag=i;}

};

若要把類complex的兩個(gè)對象com1和com2加在一起,下面的語句

是不能實(shí)現(xiàn)的:

voidmain()

(

complexcom1(1.1,2.2),com2(3.3,4.4),total;

total=com1+com2;〃錯(cuò)誤

〃???

}

錯(cuò)誤原因是類complex的類型不是基本數(shù)據(jù)類型,而是用戶自定義

的數(shù)據(jù)類型。C++還是無法直接將兩個(gè)complex類對象相加。

類外部的運(yùn)算符函數(shù)外

為了表達(dá)上的方便,人們希望預(yù)定義的內(nèi)部運(yùn)算符(如“+”、

“*”、等)在特定類的對象上以新的含義進(jìn)行解釋,如希

望能夠?qū)崿F(xiàn)tota仁com1+com2,這就需要用重載運(yùn)算符來解決。

C++為運(yùn)算符重載提供了一種方法,即在進(jìn)行運(yùn)算符重載時(shí),

必須寫一個(gè)運(yùn)算符函數(shù),其名字為operator后隨一個(gè)要重載的運(yùn)

算符。例如,要重載號,應(yīng)該寫一個(gè)名字為operator+的

函數(shù)。

---表5.1

函數(shù)功△*匕

operator+()法

operator-()

operator*()

operator/()

operator<()

7

運(yùn)算符函數(shù)operator+()

在編譯時(shí)遇到名為operator@的運(yùn)算符函數(shù)(@表示所要重

算符),就檢查傳遞給函數(shù)的參數(shù)的類型。如果編譯器在一個(gè)運(yùn)

算符的兩邊看到自定義的數(shù)據(jù)類型,就執(zhí)行用戶自己的函數(shù),而

不是常規(guī)運(yùn)算符。

若要將上述類complex的兩個(gè)對象相加,只要寫一個(gè)運(yùn)算符函數(shù)

operator+O

complexoperator+(complexom1,complexom2)

(

complextemp;

temp.real=om1.real+om2.real;

temp.imag=om1.imag+om2.imag;

returntemp;

}

我們就能方便的使用語句total=com1+com2;

將類complex的兩個(gè)對象com1和com2相力口。

也可以使用以下的調(diào)用語句,將兩個(gè)complex類對象相加:

total=operator+(com1,com2);

這兩個(gè)調(diào)用語句是等價(jià)的,但顯然后者不如前者簡明和方便。

例5.2運(yùn)算符函數(shù)operator+()將兩個(gè)compIex類對象相加程序

#include<iostream.h>

classcomplex{

public:

doublereal;

doubleimaa:

Voidmain()

{complexcom1(1.1,2.2),com2(3.3,4.4),total1,total2;

total1=operator+(com1,com2);〃調(diào)用運(yùn)算符函數(shù)operator+O

的第一種方式

cout?"real1="?total1.reaK<5

,,?"imag1="?total1.imag?endl;

total2=com1+com2;〃調(diào)用運(yùn)算符函數(shù)operator+()的第二種方

coutvv"real2="vvtotal2,realvv”

,,?"imag2="?total2.imag?endl;

)

程序運(yùn)行結(jié)果為:

real1=4.4imag1=6.6

reaI2=4.4imag2=6.6

綜合說明:<

(1)運(yùn)算符重載函數(shù)operator@O可以返回任何類型,甚至可以是void類型

但通常返回類型與它所操作的類的類型相同,這樣可以使重載運(yùn)算符用在復(fù)

雜的表達(dá)式中。

(2)在重載運(yùn)算符時(shí),運(yùn)算符函數(shù)所作的操作不一定要保持C++中該運(yùn)算符原

有的含義。例如,可以把加運(yùn)算符重載成減操作,但這樣容易造成混亂。所

以保持原含義,容易被接受,也符合人們的習(xí)慣。

(3)在C++中,用戶不能定義新的運(yùn)算符,只能從C++已有的運(yùn)算符中選擇一

個(gè)恰當(dāng)?shù)倪\(yùn)算符重載。

(4)C++編譯器根據(jù)參數(shù)的個(gè)數(shù)和類型來決定調(diào)用哪個(gè)重載函數(shù)。因此,可以

為同一個(gè)運(yùn)算符定義幾個(gè)運(yùn)算符重載函數(shù)來進(jìn)行不同的操作

(5)重載運(yùn)算符與預(yù)定義運(yùn)算符的使用方法完全相同,它不能改變原有運(yùn)算符

的參數(shù)個(gè)數(shù)(單目或雙目),也不能改變原有的優(yōu)先級和結(jié)合性。

(6)在C++中,大多數(shù)系統(tǒng)預(yù)定義的運(yùn)算符都能被重載,例如

*

+J.,*1/0%/A&?I1

■1=<>+=?*=

/=%=A=&=1=???=

?===1■=<=>=&&II++

■■[]0newdelete

也有一些運(yùn)算符是不能被重載的,如:

*..Q>

前處如符號癡##也不露重載。

5.3.2友元運(yùn)算符函數(shù)I<

把運(yùn)算符函數(shù)定義成某個(gè)類的友元函數(shù),稱為友元運(yùn)算符

函數(shù)。

1.友元運(yùn)算符函數(shù)定義的語法形式

友元運(yùn)算符函數(shù)在類的內(nèi)部聲明格式如下:

classX{

//.....

friend返回類型operator運(yùn)算符(參數(shù)表);

//.....

);

11

在類外,友元運(yùn)算符函數(shù)與定義一般的友元函數(shù)相似,其

格式如下:

返回類型operator運(yùn)算符(參數(shù)表)

〃函數(shù)體

}

由于友元函數(shù)不是類的成員函數(shù),所以不需要綴上類名。

與成員運(yùn)算符函數(shù)不同,友元運(yùn)算符函數(shù)是不屬于任何

類對象的,它沒有this指針。若重載的是雙目運(yùn)算符,

則參數(shù)表中有兩個(gè)操作數(shù);若重載的是單目運(yùn)算符,則

參數(shù)表中只有一個(gè)操作數(shù)。

12

2.雙目運(yùn)算符重載

當(dāng)用友元函數(shù)重載雙目運(yùn)算符時(shí),兩個(gè)操作數(shù)都要傳給運(yùn)

算符函數(shù)。

例5.3友元函數(shù)重載雙目運(yùn)算符

個(gè)

數(shù)a+bi和c+di進(jìn)行加、減、乘、除的方法如下:

(a+bi)+(c+di)=(a+c)+(b+d)i

法(a+bi)-(c+di)=(a-c)+(b-d)i

除(a+bi)*(c+di)=(ac-bd)+(ad+bc)i

(a+bi)/(c+di)=((a+bi)*(c-di))/(c*c+d*d)

13

#include<iostream.h>

classcomplex{

private:

doublereal;

doubleimag;

public:

complex(doubler=0.0,double1=0.0){real=r;imag=i;}

voidprint();

friendcomplexoperator+(complexa,complexb);

//相友元運(yùn)算符函數(shù)重載復(fù)數(shù)

friendcomplexoperator-(complexa,complexb);

〃用友元運(yùn)算符函數(shù)重載魚數(shù)

friendcomplexoperator*(complexa,complexb);

〃用友元運(yùn)算符函數(shù)重載復(fù)數(shù)

friendcomplexoperator/(complexa,complexb);

〃用友元是算符函藪重載復(fù)數(shù)

);

14

接1例5.3

complexoperator+(complexa,complexb)〃重載“十”定義

{complextemp;

temp.real=a.real+b.real;temp.imag=a.imag+b.imag;

returntemp;

}

complexoperator-(complexa,complexb)〃重載定義

{complextemp;

temp.real=a.real-b.real;temp.imag=a.imag-b.imag;

returntemp;

)

complexoperator(complexa,complexb)〃重載定義

{complextemp;

temp.real=a.rearb.real-a.imag*b.imag;

temp.imag=a.rearb.imag+a.imag*b.real;

returntemp;

)15

接2例5.5

complexoperator/(complexa,complexb)〃重載定義

{complextemp;

doublet;

t=1/(b.rearb.real+b.imag*b.imag);

temp.real=(a.rearb.real+a.imag*b.imag)*t;

temp.imag=(b.reara.imag-a.real*b.imag)*t;

returntemp;

}

voidcomplex::print()〃輸出顯示復(fù)數(shù)

(

cout?real;

if(imag>0)cout?u+,5;

if(imag!=0)cout?imag?^^i\n^^

}16

voidmain()

{complexAl(2,3,4.6),A2(3,6,2.8),

A3,A4,A5,A6;〃定義6個(gè)復(fù)數(shù)對象

A3=A1+A2;〃復(fù)數(shù)相加

A4=A1-A2;〃復(fù)數(shù)相減

A5=A1*a2;〃復(fù)數(shù)相乘

A6=A1/A2;〃復(fù)數(shù)相除

A1.print();〃輸出復(fù)數(shù)A1

A2.print();〃輸出復(fù)數(shù)A2

A3.print();〃輸出復(fù)數(shù)相加結(jié)果A3

A4.print();〃輸出復(fù)數(shù)相減結(jié)果A4

A5.print();〃輸出復(fù)數(shù)相乘結(jié)果A5

A6.print();〃輸出復(fù)數(shù)相除結(jié)果A6

17

程序運(yùn)行結(jié)果如下:

2.3+4.6i

3.6+2.8i

5.9+7.4i

13+18

-4.6+23i

1.017308+0.486538i

調(diào)用時(shí):

aa@bb;//隱式調(diào)用

opreator@(aa,bb)〃顯式調(diào)用

18

3.單目運(yùn)算符重載<

用友元函數(shù)重載單目運(yùn)算符時(shí),需要一個(gè)顯式的操作數(shù)。

例5.4用友元函數(shù)重載單目運(yùn)算符“-”例.子。,

#include<iostream.h>voidmian()

classAB{{ABob1(50,60),ob2;

inta,b;ob1.show();

public:ob2="ob1;

AB(intx=0,inty=0){a=x;b=y;}ob2.show();

friendABoperator-(ABobj);〃聲}、一、_

voidshow();

);

ABoperator-(ABob|)〃定義重載單目運(yùn)算符

{obj.a=-obj.a;obj.b=-obj.b;returnobj;}

voidAB::show()

{cout?ua,,,,?au<,,=,,?b?end}

程序運(yùn)行結(jié)果如下:

a=50b=60

3=-50b=-6019

仗m漢/L四姒里秋丁丁.,-------心q十口^心舁1可,HJ日匕云可以心口IT

喻5.5

ttinclude<iostream.h>

classcoord{

intx,y;

public:

coord(inti=0,intj=0){x=i;y=j;}

voidprint(){cout<<〃x:〃〈〈x〈〈〃,y:〃〈〈y〈〈endl;}

friendcoordoperator++(coordop);

);

coordoperator++(coordop)

{++op.X;

++op.y;

returnop;

20

voidmain()

{coordob(10,20);

ob.print();

operator++(ob);//顯式調(diào)用

ob.print();

++ob;//隱式調(diào)用

ob.print();

)

運(yùn)行結(jié)果:

x:10,y:20

x:10,y:20

x:10,y:20

這個(gè)運(yùn)行結(jié)果沒有達(dá)“++”的目的,由于友元函數(shù)沒有this指針,

所以不能引用this指針?biāo)傅膶ο?。這個(gè)函數(shù)是通過傳值的方法

傳遞參數(shù)的,函數(shù)體內(nèi)對。P的所以修改都無法傳到函數(shù)體外。因

止匕在operator++函數(shù)中,任何內(nèi)容的改變不會(huì)影響產(chǎn)生調(diào)用的

操作數(shù),也就是說。實(shí)際上對象x和y并未增加。21

為了解決以上問題,使用友元函數(shù)重載單目運(yùn)算符“++”匚力

“一”時(shí),應(yīng)采用引用參數(shù)傳遞操作數(shù)(&),這樣函數(shù)參數(shù)的任何改

變都影響產(chǎn)生調(diào)用的操作數(shù),從而保持了兩個(gè)運(yùn)算符的原意。

例5.6使用友元運(yùn)算符函數(shù)重寫例5.5的程序。

#include<iostream.h>

classcoord{

intx,y;

public:

coord(inti=O,intj=0){x=i;y=j;}

voidprint(){cout?ux:"?x?u,y:^?y?endl;}

friendcoordoperator++(corrd&op);

〃聲明友元運(yùn)算符函數(shù),形參為引用

};

coordoperator++(coord&op)〃定義友元運(yùn)算符函數(shù)

{++op.x;

++op.y;

returnop;

}22

voidmain()

{coordob(10,20);

ob.print();

++ob;〃隱式調(diào)用友元運(yùn)算符函數(shù)

ob.print();

operator++(ob);〃顯式調(diào)用友元運(yùn)算符函數(shù)

ob.print();

)

程序運(yùn)行的結(jié)果如下:

x:10,y:20

x:11,y:21

x:12,y:22

23

當(dāng)用友元函數(shù)重載單目運(yùn)算符時(shí),參數(shù)表中有一個(gè)操作數(shù)

一般而言,采用友元函數(shù)重載單目運(yùn)算符@后,可以采用以下

兩種方法來使用:

@aa;〃隱式調(diào)用

operator@(aa);〃顯式調(diào)用

綜合說明:

(1)不能用友元函數(shù)重載的運(yùn)算符是:=,(),[],?>其余的

運(yùn)算符都可以使用友元函數(shù)來實(shí)現(xiàn)重載。

(2)由于單目運(yùn)算符“?”可不改變操作數(shù)自身的值,所以在例5.4

載單目運(yùn)算符的友元運(yùn)算符函數(shù)的原型可寫成:

friendABoperator-(ABobj);

通過傳值的方式傳遞參數(shù)。

24

5.3.3成員運(yùn)算符函數(shù)<

運(yùn)算符函數(shù)可以定義為類的成員(稱為成員運(yùn)算符函數(shù))

1.成員運(yùn)算符函數(shù)定義的語法形式

成員運(yùn)算符函數(shù)的原型在類的內(nèi)部聲明格式為:

classX{

//...

返回類型operator運(yùn)算符(形參表);

//...

};

類外成員運(yùn)算符函數(shù)定義的更一般形式為:

返回類型X:operator運(yùn)算符(形參表)

//函數(shù)體

}

在成員運(yùn)算符函數(shù)的參數(shù)表中,若運(yùn)算符是單目的,則參

數(shù)表為空;若運(yùn)算符是雙目的,則參數(shù)表中有一個(gè)操作

數(shù)。

2.雙目運(yùn)算符重載<

對雙目運(yùn)算符而言,成員運(yùn)算符函數(shù)的參數(shù)表中僅有一個(gè)

參數(shù),它們?yōu)檫\(yùn)算符的右操作數(shù),此時(shí)當(dāng)前對象作為運(yùn)

算符的左操作數(shù),它們通過this指針隱含地傳遞給函數(shù)

的。例如:

classX{

〃…

intoperator+(Xa);

);

在類X中聲明了重載“十”的成員運(yùn)算符函數(shù),返回類型為

int,它具有兩個(gè)操作數(shù),一個(gè)是當(dāng)前對象,另一個(gè)是

對象a。

例5.7用雙目運(yùn)算符函數(shù)進(jìn)行復(fù)數(shù)運(yùn)算的例子

26

#include<iostream.h>

classcomplex{

private:

doublereal;〃復(fù)數(shù)的實(shí)數(shù)部分

doubleimag;〃復(fù)數(shù)的虛數(shù)部分

public:

complex(doubler=0.0,doublei=0.0);〃構(gòu)造函數(shù)

voidprint();〃顯示輸出復(fù)數(shù)

complexoperator+(complexc);〃重載復(fù)數(shù)運(yùn)算

complexoperator-(complexc);〃重載復(fù)數(shù)“一”運(yùn)算

complexoperator*(complexc);〃重載復(fù)數(shù)“釬運(yùn)算

complexoperator/(complexc);〃重載復(fù)數(shù)運(yùn)算

);27

complex::complex(doubler,doublei)〃定義構(gòu)造函數(shù)

接1例5.7

complexcomplex::operator+(complexc)〃重載定義

complextemp;

temp.real=real+c.real;

temp.imag=imag+c.imag;

returntemp;

)

complexcomplex::operator-(complexc)〃重載定義

(

complextemp;

temp.real=real-c.real;

temp.imag=imag-c.imag;

returntemp;

)

28

接2例5.7

complexcomplex::operator*(complexc)〃重載“*F

(

complextemp;

temp.real=real*c.real-imag*c.imag;

temp.imag=imag*c.real+rearc.imag;

returntemp;

)

complexcomplex::operator/(complexc)〃重載定義

(

complextemp;

doublet;

t=1/(c.rearc.real+c.imag*c.imag);

temp.real=(rearc.real+imag*c.imag)*t;

temp.imag=(c.rearimag-rearc.imag)*t;

returntemp;

)29

接3例5.7

voidcomplex::print()〃顯示復(fù)數(shù)的實(shí)數(shù)部分和虛g

{cout?real;

if(imag>0)cout?,,+";

if(imag!=0)cout?imag?"i\n";

)

voidmain()

{complexA1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6;//定義六個(gè)復(fù)

數(shù)類對象

A3=A1+A2;〃復(fù)數(shù)相加

A4=A1-A2;〃復(fù)數(shù)相減程序運(yùn)行結(jié)果如下:

A5=A1*A2;〃復(fù)數(shù)相乘2.3+4.6i

A6=A1/A2;〃復(fù)數(shù)相除3.6+2.8i

A1.print();〃輸出復(fù)數(shù)A15.9+7.4i

A2.print();〃輸出復(fù)數(shù)A2-1.3+1.8i

A3.print();〃輸出復(fù)數(shù)相加的結(jié)身

-4.6+23i

A4.print();〃輸出復(fù)數(shù)相減的結(jié)身1017308+0486?8i

A5.print();〃輸出復(fù)數(shù)相乘的結(jié)果!-017308+0.4865381

A6.print();〃輸出復(fù)數(shù)相除的結(jié)果A6

30

}

在主函數(shù)main()中的語句|.

A3=A1+A2;一—

A4=A1-A2;

A5=A1*A2;

A6=A1/A2;

所用的運(yùn)算符“+”、"-”、“*"、“/”是重載后的運(yùn)算符。程序

執(zhí)行到這四條語句時(shí)C++將其解釋為:

A3=A1.operator+(A2);

A4=A1.operator-(A2);

A5=A1.operator*(A2);

A6=A1.operator/(A2);

由此我們可以看出,成員運(yùn)算符函數(shù)operator@實(shí)際上是由雙目

運(yùn)算符左邊的對象A1調(diào)用的,盡管雙目運(yùn)算符函數(shù)的參數(shù)表只

有一個(gè)操作數(shù)A2,但另一個(gè)操作數(shù)是由對象A1通過this指針隱

含地傳遞的。以上兩組語句的執(zhí)行結(jié)果是完全相同的。一般而言,

采用成員函數(shù)重載雙目運(yùn)算符@后,可以用以下兩種方法來使用:

aa@bb;〃隱式調(diào)用

aa.operator@(bb);〃顯式調(diào)用

成員運(yùn)算符函數(shù)operator@所需的一個(gè)操作數(shù)由對象aa通過this

指針隱含地傳遞。因此,它的參數(shù)表中只有一個(gè)操作數(shù)bbB

3.單目運(yùn)算符重載<

對單目運(yùn)算符而言,成員運(yùn)算符函數(shù)的參數(shù)表中沒有參數(shù),此時(shí)當(dāng)

前對象作為運(yùn)算符的一個(gè)操作數(shù)。

例5.8重載單目運(yùn)算符“++”的例子

#include<iostream.h>

classcoord{

intx,y;

public:

coord(inti=O,intj=0);

voidprint();

coordoperator++();〃聲明成員運(yùn)算符函數(shù)operator++()

);

coord::coord(inti,intj){x=i;y=j;}

voidcoord::print(){cout?"x:"<<x?",y:"?y?endl;}

coordcoord::operator++()〃定義成員運(yùn)算符函數(shù)。perator++()

{++x;

++y;

return*this;

)

32

接1例5.8

voidmain()

{coordob(10,20);

ob.print();

++ob;〃隱式調(diào)用成員運(yùn)算符函數(shù)operator++()

ob.print();

ob.operator++();〃顯式調(diào)用成員運(yùn)算符函數(shù)operator++()

ob.print();

)

程序運(yùn)行結(jié)果如下:

x:10,y:20

x:11,y:21

x;12,y=22

不例主函數(shù)main()中調(diào)用成員運(yùn)算符函數(shù)operator++()采用

了兩種方法:++ob;與ob.operator++()

兩者是等價(jià)的,其執(zhí)行效果是完全相同的。

從本例還可以看出,當(dāng)成員函數(shù)重載單目運(yùn)算符時(shí),沒有參數(shù)被顯

式地傳遞給成員運(yùn)算符函數(shù)。參數(shù)是通過this指針隱含地傳遞給

函數(shù)的。33

采用成員函數(shù)重載單目運(yùn)算符時(shí),可以用以下兩種方法來使用:

@aa;〃隱式調(diào)用

aa.operator@();〃顯式調(diào)用

成員運(yùn)算符函數(shù)operator@所需的一個(gè)操作數(shù)由對象aa通過this

指針隱含地傳遞。因此,在它的參數(shù)表中沒有參數(shù)。

34

5.3.4成員運(yùn)算符函數(shù)與友元運(yùn)算符函數(shù)的比較

我們對成員運(yùn)算符函數(shù)與友元運(yùn)算符函數(shù)作一比較。

(1)對雙目運(yùn)算符,成員運(yùn)算符函數(shù)帶有一個(gè)參數(shù),友元運(yùn)算符函數(shù)

帶有兩個(gè)參數(shù)對單目運(yùn)算符,成員運(yùn)算符函數(shù)不帶參數(shù),友元運(yùn)算

符函數(shù)帶有一個(gè)參數(shù)。

(2)雙目運(yùn)算符一般可以被重載為友元運(yùn)算符函數(shù)或成員運(yùn)算符函

數(shù),但有一種情況,必須使用友元函數(shù)。

例如,在例5.4的類AB中,用成員運(yùn)算符函數(shù)重載運(yùn)算

ABAB::operator+(intx)

ABtemp;

temp.a=a+x;

temp.b=b+x;

returntemp;

35

若類AB的對象ob要做賦值運(yùn)算和加法運(yùn)算,以下是一條正確的語句

ob=ob+100;

由于對象ob是運(yùn)算符的左操作數(shù),所以它調(diào)用了運(yùn)算符重

載函數(shù),把一個(gè)整數(shù)加到了對象ob的某些元素上去。然而,下一條

語句就不能工作了:

ob=100+ob;

不能工作的原因是運(yùn)算符的左操作數(shù)是一個(gè)整數(shù),而整數(shù)是一個(gè)內(nèi)

部數(shù)據(jù)類型,100不能產(chǎn)生對成員運(yùn)算符函數(shù)的調(diào)用。

36

用兩種形式的友元函數(shù)來重載運(yùn)算符函數(shù)“+”

就能消除由于運(yùn)算符的左操作數(shù)是內(nèi)部數(shù)據(jù)類型而帶來的問題,

下述程序說明了如何實(shí)現(xiàn)。

例5.9用兩種形式的友元函數(shù)來重載運(yùn)算符函數(shù)

#include<iostream.h>

classAB{

inta,b;

public:

AB(intx=O,inty=0){a=x;b=y}

friendABopterator+(ABob,intx);

〃聲明一種友元運(yùn)算符函數(shù)

friendABopterator+(intx,ABob);

〃聲明另一種友元運(yùn)算符函數(shù)

voidshow();

);

37

接1例5.9

ABoperator+(ABob,intx)

〃定義常規(guī)類型在右邊的友元運(yùn)算符函數(shù)

{ABtemp;

temp.a=a+x;

temp.b=b+x;

returntemp;

)

ABoperator+(intx,ABob)

〃定義常規(guī)類型在左邊的友元運(yùn)算符函數(shù)

ABtemp;voidmain()

temp.a=x+ob.a;{ABob1(30,40),ob2;

temp.b=x+ob.b;

ob2=ob1+30;

returntemp;ob2.show();

)ob2=50+ob1;

voidAB::show()

,,,ob2.show();

{coutvv"a=''vvavv''u?b=<<b<<k}

(3)成員運(yùn)算符函數(shù)和友元運(yùn)算符函數(shù)都可以用習(xí)慣方式調(diào)—

也可以用它們專用的方式調(diào)用,表5.2列出了一般情況下運(yùn)算符

函數(shù)的調(diào)用形式。

習(xí)慣形式友元運(yùn)算符函數(shù)調(diào)用形式成員運(yùn)算符函數(shù)調(diào)用形式

a+boperator+(a,b)a.operator+(b)

-aoperator-(a)a.operator-()

a++operator++(a,0)a.operator++(0)

(4)C++的大部分運(yùn)算符既可說明為成員運(yùn)算符函數(shù),又可說明

為友元運(yùn)算符函數(shù)。究竟選擇哪一種運(yùn)算符函數(shù)好一些,沒有定

論,這主要取決于實(shí)際情況和程序員的習(xí)慣。

一般而言,對于雙目運(yùn)算符,將它重載為一個(gè)友元運(yùn)算符函數(shù)

比重載為一個(gè)成員運(yùn)算符函數(shù)便于使用。若一個(gè)運(yùn)算符的操作需

要修改類對象的狀態(tài),則選擇成員運(yùn)算符函數(shù)較好。如果運(yùn)算符

所需的操作數(shù)(尤其是第一個(gè)操作數(shù))希望有隱式類型轉(zhuǎn)換,則

運(yùn)算符重載必須用友元函數(shù),而不能用成員函數(shù)。39

有以下的經(jīng)驗(yàn):

?對于單目運(yùn)算符,建議選擇成員函數(shù);

?對于運(yùn)算符J、()、[]、-〉”只能作為成員函數(shù);

?對于運(yùn)算符“+二、一二、/二、*二、&=>!=>?二、%二、>>=>

〈〈二”,建議重載為成員函數(shù);

?對于其他運(yùn)算符,建議重載為友元函數(shù)。

40

5.3.5“++”和“--”的重載<

運(yùn)算符“++”和“--”放置在變量的前面與后面,其作用是有區(qū)別

的。但是C++2.1之前的版本在重載“++”(或“--”)時(shí),不能

顯式地區(qū)分是前綴還是后綴方式。也就是說,在例5.8的main()

函數(shù)中,以下兩條語句是完全相同的:

ob++;++ob;

在C++2.1及以后的版本中,編輯器可以通過在運(yùn)算符函數(shù)參數(shù)表中

是否插入關(guān)鍵字int來區(qū)分這兩種方式。

(1)前綴方式++ob,可以用運(yùn)算符函數(shù)重載為:

ob.operator++();//成員函數(shù)重載

operator++(X&ob);//友元函數(shù)重載,其中ob為X類對象

⑵后綴方式ob++,可以用運(yùn)算符函數(shù)重載為:

ob.operator++(int);〃成員函數(shù)重載

operator++(X&ob,int);〃友元函數(shù)重載

調(diào)用時(shí),參數(shù)int一般用0值。

重載運(yùn)算符“--”也可用類似的方法。

41

例5.10包含“++”和“一”兩種重載運(yùn)算符

#include<iostream.h>

#include<iomanip.h>

classover{

inti1,i2,i3;

public:

voidinit(int11,intI2,intI3){i1=l1;i2=l2;i3=l3;}

〃給數(shù)據(jù)成員賦初值

voidprint();{cout?ui1:"vvilvv“i2:"vvi2vv”

i3:?i3?endl;〃顯示輸出數(shù)據(jù)成員

overoperator++();〃成員函數(shù)重載“++”(前綴方式)聲

overoperator++(int);//成員函數(shù)重載“++”(后綴方式)聲

friendoveroperator--(over&);

〃友元函數(shù)重載(前綴方式)聲

42

friendoveroperator--(over&,int);

接1例5.10<

overover::operator++()〃定義成員函數(shù)重載(前綴方式)

{++i1;++i2;++i3;

return*this:

)

overover::operator++(int)〃定義成員函數(shù)重載++”(后綴方式)

{i1++;i2++;i3++;

return*this;

)

overoperator--(over&op)〃定義友元函數(shù)重載(前綴方

式)

{--op.il;--op.i2;--op.i3;

returnop;

}

overoperator--(over&op,int)//定義友元函數(shù)重載(后綴方

式)

{op.i1--;op.i2-op.i3--;43

returnop;

接2例5.10

Voidmain()

{overobj1,obj2,obj3,obj4;

nhi125V

程序運(yùn)行結(jié)果如下:

i1:5i2:3i3:6

i1:3i2:6i3:10

i1:7i2:2i3:7

i1:2i2:5i3:6

i2:4i3:7

i2:7i3:11

i2:1i3:6

i2:4i3:5

以上例子中,使用成員函數(shù)分別以前綴方式和后綴方式重載了運(yùn)算

符“十+”,使用友元函數(shù)分別以前綴方式和后綴方式重載了運(yùn)算符

ODJi.pnnqj;oojz.pnnq);oojo.pnnq);ooj4.prinq);44

}

5.3.6賦值運(yùn)算符“二”的重載<

對任一類X,如果沒有用戶自定義的賦值運(yùn)算符函數(shù),那么系統(tǒng)將

自動(dòng)地為其生成一個(gè)默認(rèn)的賦值運(yùn)算符函數(shù),例如:

X&X::operator=(constX&source)

(

〃成員間賦值

)

若obj1和obj2是類X的兩個(gè)對象,。均2已被創(chuàng)建,則編譯程序遇到

如下語句:

obj1=obj2;

就調(diào)用默認(rèn)的賦值運(yùn)算符函數(shù),將對象。32的數(shù)據(jù)成員逐域拷貝到

對象objl中。

通常,默認(rèn)的賦值運(yùn)算符函數(shù)是能夠勝任工作的。但在某些特殊情

況下,如類中有指針類型時(shí),使用默認(rèn)賦值運(yùn)算符函數(shù)會(huì)產(chǎn)生錯(cuò)

誤,這個(gè)錯(cuò)誤叫“指針懸掛”,這時(shí)程序員不得不自行重載賦值

運(yùn)算符,請看下面的例子。

1.指針懸掛問題45

例5.11

#include<iostream.h>

#include<string.h>

classstring{

char*ptr;

public:

string(char*s)voidmain()

{ptr=newchar[strk{stringp1("chen");

strcpy(ptr,s);{stringp2("");

}p2=p1;//string類對象間賦值

~string(){deleteptr;cont?"p2:";

voidprint(){cont?|p2.print();

);}

程序運(yùn)行結(jié)果如下:cout?"p1:";

p2:chenp1.print();

pl:□早□早)

NullPointassignment

46

接1例5.11

運(yùn)行上述程序輸出pl時(shí)發(fā)生錯(cuò)誤。原因是執(zhí)行到賦值語句p2二pl時(shí),

實(shí)際是使對象p2的指針ptr與對象pl的指針ptr指向new開辟的同

一個(gè)空間。當(dāng)p2的生命周期(內(nèi)層的一對花括號間)結(jié)束時(shí),系

統(tǒng)自動(dòng)調(diào)用析構(gòu)函數(shù)將這一空間撤消。這樣,P2中的ptr原來所

指向的區(qū)域被封鎖起來,并不能再被使用,這就產(chǎn)生了指針懸掛

問題。這時(shí)盡管pl的指針ptr存在,其所指向的空間卻無法訪問

了,如圖所示。當(dāng)pl的生命走其結(jié)束時(shí),將再次調(diào)用析構(gòu)函數(shù),

釋放同一空間,從而導(dǎo)致運(yùn)行錯(cuò)誤。

47

動(dòng)態(tài)空間1動(dòng)態(tài)空間2

動(dòng)態(tài)空間2

(b)執(zhí)行P2二Pl之后(c)p2的生命周期結(jié)束后

48

2.顯式地定義一個(gè)賦值運(yùn)算符重載函數(shù),解決指針懸掛問題I<

例5.12顯式地定義一個(gè)賦值運(yùn)算符重載函:voidmain()

存儲(chǔ)區(qū)。#include<iostream.h>{stringp1("chen");

#include<string.h>

classstring{{stringp2("");

char*ptr;p2=p1;

public:cout?"p2:";

string(char*)p2.print();

{ptr=newchar[strlen(s)+1];

strcpy(ptr,s);}

)cout?"p1:";

-string(){deleteptr;}p1.print();

voidprint(){count?ptr?endl;})

string&operator=(conststring&);〃聲也火隊(duì)'I且心畀里軌田

);

string&string::opertor=(conststring&s)〃定義賦值運(yùn)算符重載

{if(this==&s)return*this;程序運(yùn)行結(jié)果如下:

deleteptr;

ptr=newchar[strlen(s.ptr)+1];p2:chen

strcpy(ptr,s.ptr);pl:chen

return*this;

說明:<

⑴賦值運(yùn)算符“二”只能重載為成員函數(shù),而不能把它重載為友元

函數(shù),因?yàn)槿舭焉鲜鲑x值運(yùn)算符“二”重載為友元函數(shù):

friendstring&operator=(string&p2,string&p1)

這時(shí),表達(dá)式:p1="chen^^

將被解釋為:operator=(p1Jchen")這顯然是沒有什么問題的,

但對于表達(dá)式"chen"=p1

將被解釋為:operator=("cherT,p1)

即C++編譯器首先將“chen”轉(zhuǎn)換成一個(gè)隱藏的string對象,然后

使用對象p2引用該隱藏對象,編譯器不認(rèn)為這個(gè)表達(dá)式是錯(cuò)誤

的,從而將導(dǎo)致賦值語句上的混亂。因此雙目賦值運(yùn)算符應(yīng)重載

為成員函數(shù)的形式,而不能重載為友元函數(shù)的形式。

(2)類的賦值運(yùn)算符“二”可以被重載,但重載了的運(yùn)算符函數(shù)

operator=()不能被繼承。

50

537下標(biāo)運(yùn)算符“[廠的重載二

C++中運(yùn)算符“口”可作數(shù)組下標(biāo),下標(biāo)運(yùn)算符的一般使用格式為:

〈基本表達(dá)式〉[〈表達(dá)式〉]

我們可以對運(yùn)算符“[廠進(jìn)行重載,使它起別的作用。

在重載“[『時(shí),C++也把它看成雙目運(yùn)算符,例如X[Y]可看成

[]雙目運(yùn)算符

X左操作數(shù)

Y右操作數(shù)

設(shè)X是某個(gè)類的對象,類中定義了重載下標(biāo)運(yùn)算符

operator□函數(shù)。

則表達(dá)式X[5];

可被解釋為:X.operator[](5);

對運(yùn)算符“口”重載定義只能使用成員函數(shù),其形式如下:

返回類型類名::operator[](形參)

(

II函數(shù)體

}注意:形參只能有一個(gè)。51

重載運(yùn)算符“[廠來處理數(shù)組成員的例子■<

例5.13

#include<iostream.h>

#include<stdlib.h>

classVector4{

private:

intv[4];

public:

Vector4(inta1,inta2,inta3,inta4)

{v[0]=a1;v[1]=a2;v[2]=a3;v[3]=a4;}

);

voidmain()

(

Vector4v(1,2,3,4);

cout?v[2];〃出錯(cuò),不能訪問私有成員。

)

52

即使把intv[4];改為公有成員也出錯(cuò)。要用v.v[2]

我們可用重載運(yùn)算符“[『的方法,方便的引用數(shù)組成員。

例5.14

#include<iostream.h>

#include<stdlib.h>

classVector4{

private:

intv[4];

public:

Vector4(inta1,inta2,inta3,inta4)

{v[0]=a1;v[1]=a2;v[2]=a3;v[3]=a4;}

int&operator[](intbi)

{if(bi<0||bi>=4){

coutvv”數(shù)疝下標(biāo)出界!\n”;

exit(1);

)

returnv[bi];

}

);53

接1例5.14<

voidmain()

(

Vector4v(1,2,3,4);

cout?v[2]?endl;

v[3]=v[2];

cout?v[3]?endl;

v[2]=22;

cout?v[2]?endl;

)

?在上述程序中,并沒有創(chuàng)建Vector4的對象數(shù)組。程序中的下標(biāo)

被重載,以便在使用Vector4的對象內(nèi)的數(shù)組成員時(shí),用一種特

殊的方式工作。下標(biāo)總是返回和下標(biāo)對應(yīng)的對象內(nèi)數(shù)組成員的那

個(gè)元素

?重載下標(biāo)運(yùn)算符”『時(shí),返回一個(gè)int的引用,可使重載的“[廠

用的賦值語句的左邊,因?yàn)樵趍ain。中,可對某個(gè)數(shù)組成員元

素v口賦值。這樣,雖然v□是私有的,main()還是能夠直接對其

賦值,而不需要使用函數(shù)init()54

?在上述程序中,設(shè)有對下標(biāo)的檢驗(yàn),以確保被賦值的數(shù)組/L4」

存在,當(dāng)程序中一旦出現(xiàn)向超出所定義的數(shù)組下標(biāo)范圍的數(shù)組元素

的賦值,便自動(dòng)終止程序,以免造成不必要的破壞。

■與函數(shù)調(diào)用運(yùn)算符“()”一樣,下標(biāo)運(yùn)算符“[『不能用友元函數(shù)

重載,只能采用成員函數(shù)重載。

下面再舉一個(gè)很有意思的例子:

例如,可以對string數(shù)據(jù)類型定義以下的”丁運(yùn)算符重載函數(shù):

classstring{

char*ptr;

II....................

public:

string(constchar*);

char&operator[](int);

II....................

);

55

其中重載“[]”的operator函數(shù)定義為:

char&string::opertor[](intI){returnptr[l];}

由于5什M9::(^6「210「[]()的返回值在這里是一個(gè)(^2「&,所以函數(shù)

可以被用于一個(gè)賦值運(yùn)算符的任一邊,例如:

stringop="abed";

op[1]=op[3];

相當(dāng)與:op.operator[](1)=op.operator1](3);

因而op的薪值為“aded”

56

5.3.8函數(shù)調(diào)用運(yùn)算符“()”的重載

C++中運(yùn)算符“()”可作函數(shù)調(diào)用,函數(shù)調(diào)用的一般使用格式為:

〈函數(shù)名〉(〈實(shí)參表〉)

我們可以對運(yùn)算符“()”進(jìn)行重載,使它起別的作用。

在重載“()”時(shí),C++也把它看成雙目運(yùn)算符,例如X(Y)可看成

()雙目運(yùn)算符

X左操作數(shù)

Y右操作數(shù)

設(shè)X是某個(gè)類的對象,類中定義了重載下標(biāo)運(yùn)算符“()”:

operator()函數(shù)。

則表達(dá)式X(5);

可被解釋為:X.operator()(5);

對運(yùn)算符“口”重載定義只能使用成員函數(shù),其形式如下:

返回類型類名::operator()(形參表)

(

II函數(shù)體

}注意:形參只能有一個(gè)。L

例5.15

#include<iostream.h>

classMatrix{

int*m;

introw,col;

public:

Matrix(int,int);

int&operator()(int,int);〃聲明重載運(yùn)算符“()”函

數(shù)

);

Matrix::Matrix(introw,intcol)〃構(gòu)造函數(shù)

{this->row=row;

this->col=col;

m=newint[row*col];

for(inti=0;i<row*col;i++

*(m+i)=i;

)

int&Matrix::operator()(intr,intc)〃定義重載運(yùn)算符“()”函

數(shù)

(

return(*(m+r*col+c));〃取第r行第c列的元素

}

voidmain()

{

MatrixaM(10,10);〃生成對象aM

cout?aM(3,4);

〃重載運(yùn)算符“()”的調(diào)用,可解釋為

aM.perator()(3,4)

aM(3,4)=35;

〃重載運(yùn)算符“()”的調(diào)用,由于引用,可放左邊

cout?endl?aM(3,4)?endl;

}N

運(yùn)行結(jié)果:

Q4

再如:對運(yùn)算符“O”進(jìn)行重載,使它起別的作甫出一

我們知道,雙目運(yùn)算符是由左邊的對象產(chǎn)生對operator函數(shù)調(diào)用的。

This指針總是指向產(chǎn)生調(diào)用的對象。重載運(yùn)算符“()”的

operator函數(shù)可以帶任何類型的操作數(shù),返回任何有效的類型。

下面的程序?qū)椭覀兝斫夂瘮?shù)謖用運(yùn)算符“()”的重載。

設(shè)obj是類myclass的對象,而且類myclass中定義了重載函數(shù)調(diào)

用運(yùn)算符“()”,它起的作用是能把對象。bj的數(shù)據(jù)擴(kuò)大k倍

和m倍。

對應(yīng)的運(yùn)算符函數(shù)為myclassoperator()(intk,intm)

則函數(shù)調(diào)用(把對象。bj的數(shù)據(jù)擴(kuò)大10倍和100倍)

obj(10,100);

可被解釋為:obj.operator()(10,100);

60

例5.16運(yùn)算符“()的重載。—

#include<iostream.h>

classmyclass{

inti;

floatj;

public:

myclass(intx=0,floaty=0)

{仁x;j=y;}

myclassoperator()(intk,floatm);

〃聲明重載運(yùn)算符“()”函數(shù)

voiddisplay(){00^?1?,5"?j?"\n";}

};

myclassmyclass::operator()(intk,floatm)

〃定義運(yùn)算符“()”函數(shù)

1=1*

j=j*m;〃把myclass的對象中的i放大k倍,j放大m倍。

return*this;

}

61

voidmain()

{myclassobj1(10,11.5);

obj1.display();

obj1(10,100);〃重載運(yùn)算符“O”的調(diào)用,可解

II#^jobj1.perator()(10,.100)

obj1.display();

)

程序運(yùn)行結(jié)果為:

1011.5

1001150.0

說明:函數(shù)調(diào)用運(yùn)算符“(

溫馨提示

  • 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

提交評論