C++運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)_第1頁
C++運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)_第2頁
C++運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)_第3頁
C++運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)_第4頁
C++運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

-.z.C++運算符重載的方法運算符重載的方法是定義一個重載運算符的函數(shù),在需要執(zhí)行被重載的運算符時,系統(tǒng)就自動調(diào)用該函數(shù),以實現(xiàn)相應(yīng)的運算。也就是說,運算符重載是通過定義函數(shù)實現(xiàn)的。運算符重載實質(zhì)上是函數(shù)的重載。重載運算符的函數(shù)一般格式如下:函數(shù)類型operator運算符名稱(形參表列)

{

//對運算符的重載處理}

例如,想將”+”用于ple*類(復(fù)數(shù))的加法運算,函數(shù)的原型可以是這樣的:ple*operator+(ple*&c1,ple*&c2);

在上面的一般格式中,operator是關(guān)鍵字,是專門用于定義重載運算符的函數(shù)的,運算符名稱就是C++提供給用戶的預(yù)定義運算符。注意,函數(shù)名是由operator和運算符組成,上面的operator+就是函數(shù)名,意思是“對運算符+重載”。只要掌握這點,就可以發(fā)現(xiàn),這類函數(shù)和其他函數(shù)在形式上沒有什么區(qū)別。兩個形參是ple*類對象的引用,要參為ple*類對象。在定義了重載運算符的函數(shù)后,可以說,函數(shù)operator+重載了運算符+。在執(zhí)行復(fù)數(shù)相加的表達(dá)式c1+c2時(假設(shè)c1和c2都已被定義為ple*類對象),系統(tǒng)就會調(diào)用operator+函數(shù),把c1和c2作為實參,與形參進(jìn)行虛實結(jié)合。為了說明在運算符重載后,執(zhí)行表達(dá)式就是調(diào)用函數(shù)的過程,可以把兩個整數(shù)相加也想像為調(diào)用下面的函數(shù):intoperator+(inta,intb)

{

return(a+b);

}

如果有表達(dá)式5+8,就調(diào)用此函數(shù),將5和8作為調(diào)用函數(shù)時的實參,函數(shù)的返回值為13。這就是用函數(shù)的方法理解運算符??梢栽诶?0.1程序的基礎(chǔ)上重載運算符“+”,使之用于復(fù)數(shù)相加。[例10.2]改寫例10.1,重載運算符“+”,使之能用于兩個復(fù)數(shù)相加。*include<iostream>usingnamespacestd;classple*{public:ple*(){real=0;imag=0;}ple*(doubler,doublei){real=r;imag=i;}ple*operator+(ple*&c2);//聲明重載運算符的函數(shù)voiddisplay();private:doublereal;doubleimag;};ple*ple*::operator+(ple*&c2)//定義重載運算符的函數(shù){ple*c;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidple*::display(){cout<<"("<<real<<","<<imag<<"i)"<<endl;}intmain(){ple*c1(3,4),c2(5,-10),c3;c3=c1+c2;//運算符+用于復(fù)數(shù)運算cout<<"c1=";c1.display();cout<<"c2=";c2.display();cout<<"c1+c2=";c3.display();return0;}運行結(jié)果與例10.1相同:c1=(3+4i)

c2=(5-10i)

c1+c2=(8,-6i)

請比較例10.1和例10.2,只有兩處不同:1)在例10.2中以operator+函數(shù)取代了例10.1中的ple*_add函數(shù),而且只是函數(shù)名不同,函數(shù)體和函數(shù)返回值的類型都是相同的。2)在main函數(shù)中,以“c3=c1+c2;”取代了例10.1中的“c3=c1.ple*_add(c2);”。在將運算符+重載為類的成員函數(shù)后,C++編譯系統(tǒng)將程序中的表達(dá)式c1+c2解釋為c1.operator+(c2)//其中c1和c2是ple*類的對象即以c2為實參調(diào)用c1的運算符重載函數(shù)operator+(ple*&c2),進(jìn)行求值,得到兩個復(fù)數(shù)之和??梢钥吹剑瑑蓚€程序的結(jié)構(gòu)和執(zhí)行過程基本上是相同的,作用相同,運行結(jié)果也相同。重載運算符是由相應(yīng)的函數(shù)實現(xiàn)的。有人可能說,既然這樣,何必對運算符重載呢?我們要從用戶的角度來看問題,雖然重載運算符所實現(xiàn)的功能完全可以用函數(shù)實現(xiàn),但是使用運算符重載能使用戶程序易于編寫、閱讀和維護(hù)。在實際工作中,類的聲明和類的使用往往是分離的。假如在聲明ple*類時,對運算符+,-,*,/都進(jìn)行了重載,則使用這個類的用戶在編程時可以完全不考慮函數(shù)是怎么實現(xiàn)的,放心大膽地直接使用+,-,*,/進(jìn)行復(fù)數(shù)的運算即可,十分方便。對上面的運算符重載函數(shù)operator+還可以改寫得更簡練一些:ple*ple*::operator+(ple*&c2)

{returnple*(real+c2.real,imag+c2.imag);}

return語句中的ple*(real+c2.real,imag+c2.imag)是建立一個臨時對象,它沒有對名,是一個無名對象。在建立臨時對象過程中調(diào)用構(gòu)造函數(shù)。return語句將此臨時對象作為函數(shù)返回值。請思考,在例10.2中能否將一個常量和一個復(fù)數(shù)對象相加?如c3=3+c2;//錯誤,與形參類型不匹配應(yīng)寫成對象形式,如c3=ple*(3,0)+c2;//正確,類型均為對象需要說明的是,運算符被重載后,其原有的功能仍然保留,沒有喪失或改變。通過運算符重載,擴(kuò)大了C++已有運算符的作用圍,使之能用于類對象。運算符重載對C++有重要的意義,把運算符重載和類結(jié)合起來,可以在C++程序中定義出很有實用意義而使用方便的新的數(shù)據(jù)類型。運算符重載使C++具有更強(qiáng)大的功能?更好的可擴(kuò)充性和適應(yīng)性,這是C++最吸引人的特點之一。C++運算符重載的規(guī)則C++對運算符重載定義了如下幾條規(guī)則。1)C++不允許用戶自己定義新的運算符,只能對已有的C++運算符進(jìn)行重載。例如,有人覺得BASIC中用“**“作為冪運算符很方便,也想在C++中將”**“定義為冪運算符,用”3**5“表示35,這樣是不行的。2)重載不能改變運算符運算對象(即搡作數(shù))的個數(shù)。如關(guān)系運算符“>”和“<”等是雙目運算符,重載后仍為雙目運算符,需要兩個參數(shù)。運算符“+”,“-”,“*”,“&”等既可以作為單目運算符,也可以作為雙目運算符,可以分別將它們重載為單目運算符或雙目運算符。3)重載不能改變運算符的優(yōu)先級別。例如“*”和“/”優(yōu)先于“+”和“-”,不論怎樣進(jìn)行重載,各運算符之間的優(yōu)先級別不會改變。有時在程序中希望改變*運算符的優(yōu)先級,也只能使用加圓括號的辦法強(qiáng)制改變重載運算符的運算順序。4)重載不能改變運算符的結(jié)含性。如賦值運算符是右結(jié)合性(自右至左),重載后仍為右結(jié)合性。5)重載運算符的函數(shù)不能有默認(rèn)的參數(shù),否則就改變了運算符參數(shù)的個數(shù),與前面第(2)點矛盾。6)重載的運算符必須和用戶定義的自定義類型的對象一起使用,其參數(shù)至少應(yīng)有一個是類對象(或類對象的引用)。也就是說,參數(shù)不能全部是C++的標(biāo)準(zhǔn)類型,以防止用戶修改用于標(biāo)準(zhǔn)類型數(shù)據(jù)的運算符的性質(zhì),如下面這樣是不對的:intoperator+(inta,intb){retum(a-b);}原來運算符+的作用是對兩個數(shù)相加,現(xiàn)在企圖通過重載使它的作用改為兩個數(shù)相減。如果允許這樣重載的話,如果有表達(dá)式4+3,它的結(jié)果是7呢還是1?顯然,這是絕對禁止的。如果有兩個參數(shù),這兩個參數(shù)可以都是類對象,也可以一個是類對象,一個是C++標(biāo)準(zhǔn)類型的數(shù)據(jù),如ple*operator+(inta,ple*&c){returnple*(a+c.real,c.imag);}它的作用是使一個整數(shù)和一個復(fù)數(shù)相加。7)用于類對象的運算符一般必須重載,但有兩個例外,運算符“=”和“&”不必重載。①賦值運算符(=)可以用于每一個類對象,可以利用它在同類對象之間相互賦值。我們知道,可以用賦值運算符對類的對象賦值,這是因為系統(tǒng)已為每一個新聲明的類重載了一個賦值運算符,它的作用是逐個復(fù)制類的數(shù)據(jù)成員。用戶可以認(rèn)為它是系統(tǒng)提供的默認(rèn)的對象賦值運算符,可以直接用于對象間的賦值,不必自己進(jìn)行重載。但是有時系統(tǒng)提供的默認(rèn)的對象賦值運算符不能滿足程序的要求,例如,數(shù)據(jù)成員中包含指向動態(tài)分配存的指針成員時,在復(fù)制此成員時就可能出現(xiàn)危險。在這種情況下,就需要自己重載賦值運算符。②地址運算符&也不必重載,它能返回類對象在存中的起始地址。8)從理論上說,可以將一個運算符重載為執(zhí)行任意的操作,如可以將加法運算符重載為輸出對象中的信息,將“>”運算符重載為“小于”運算。但這樣違背了運算符重載的初衷,非但沒有提髙可讀性,反而使人莫名其妙,無法理解程序。應(yīng)當(dāng)使重載運算符的功能類似于該運算符作用于標(biāo)準(zhǔn)類型數(shù)據(jù)時所實現(xiàn)的功能(如用“+”實現(xiàn)加法,用“>”實現(xiàn)“大于”的關(guān)系運算)。9)運算符重載函數(shù)可以是類的成員函數(shù),也可以是類的友元函數(shù),還可以是既非類的成員函數(shù)也不是友元函敝的普通函數(shù)。以上這些規(guī)則是很容易理解的,不必死記。把它們集中在一起介紹,只是為了使讀者有一個整體的概念,也便于查閱。C++允許重載的運算符和不允許重載的運算符C++中絕大部分的運算符允許重載,具體規(guī)定見表10.1。表10.1C++允許重載的運算符雙目算術(shù)運算符+(加),-(減),*(乘),/(除),%

(取模)關(guān)系運算符==(等于),!=(不等于),<(小于),>(大于>,<=(小于等于),>=(大于等于)邏輯運算符||(邏輯或),&&(邏輯與),!(邏輯非)單目運算符+(正),-(負(fù)),*(指針),&(取地址)自增自減運算符++(自增),--(自減)位運算符|(按位或),&(按位與),~(按位取反),^(按位異或),,<<

(左移),>>(右移)賦值運算符=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=空間申請與釋放new,delete,new[],delete[]其他運算符()(函數(shù)調(diào)用),->(成員訪問),->*(成員指針訪問),,(逗號),[](下標(biāo))不能重載的運算符只有5個:.(成員訪問運算符).*(成員指針訪問運算符)::(域運算符)sizeof(長度運算符)":(條件運算符)前兩個運算符不能重載是為了保證訪問成員的功能不能被改變,域運算符和sizeof運算符的運算對象是類型而不是變量或一般表達(dá)式,不具備重載的特征。C++運算符重載函數(shù)作為類成員函數(shù)和友元函數(shù)例10.2中對運算符“+”進(jìn)行了重載,使之能用于兩個復(fù)數(shù)的相加。在該例中運算符重載函數(shù)operator+作為ple*類中的成員函數(shù)??赡苡械淖x者會提出這樣的問題:”+“是雙目運算符,為什么在例10.2程序中的重載函數(shù)中只有一個參數(shù)呢?實際上,運算符重載函數(shù)有兩個參數(shù),由于重載函數(shù)是ple*類中的成員函數(shù),有一個參數(shù)是隱含的,運算符函數(shù)是用this指針隱式地訪問類對象的成員??梢钥吹?,重載函數(shù)operator+訪問了兩個對象中的成員,一個是this指針指向的對象中的成員,一個是形參對象中的成員。如this->real+c2.real,this->real就是c1.real。上節(jié)中已說明,在將運算符函數(shù)重載為成員函數(shù)后,如果出現(xiàn)含該運算符的表達(dá)式,如c1+c2,編譯系統(tǒng)把它解釋為:c1.operator+(c2)即通過對象c1調(diào)用運算符重載函數(shù),并以表達(dá)式中第二個參數(shù)(運算符右側(cè)的類對象c2)作為函數(shù)實參。運算符重載函數(shù)的返回值是ple*類型,返回值是復(fù)數(shù)c1和c2之和(ple*(c1.real+c2.real,c1.imag+c2.imag))。運算符重載函數(shù)除了可以作為類的成員函數(shù)外,還可以是非成員函數(shù)??梢詫⒗?0.2改寫為例10.3。[例10.3]將運算符“+”重載為適用于復(fù)數(shù)加法,重載函數(shù)不作為成員函數(shù),而放在類外,作為ple*類的友元函數(shù)。*include<iostream>usingnamespacestd;//注意,該程序在VC6.0中編譯出錯,將以上兩行替換為*include<iostream.h>即可順利通過classple*{public:ple*(){real=0;imag=0;}ple*(doubler,doublei){real=r;imag=i;}friendple*operator+(ple*&c1,ple*&c2);//重載函數(shù)作為友元函數(shù)voiddisplay();private:doublereal;doubleimag;};ple*operator+(ple*&c1,ple*&c2)//定義作為友元函數(shù)的重載函數(shù){returnple*(c1.real+c2.real,c1.imag+c2.imag);}voidple*::display(){cout<<"("<<real<<","<<imag<<"i)"<<endl;}intmain(){ple*c1(3,4),c2(5,-10),c3;c3=c1+c2;cout<<"c1=";c1.display();cout<<"c2=";c2.display();cout<<"c1+c2=";c3.display();}與例10.2相比較,只作了一處改動,將運算符函數(shù)不作為成員函數(shù),而把它放在類外,在ple*類中聲明它為友元函數(shù)。同時將運算符函數(shù)改為有兩個參數(shù)。在將運算符“+”重載為非成員函數(shù)后,C++編譯系統(tǒng)將程序中的表達(dá)式c1+c2解釋為operator+(c1,c2)即執(zhí)行c1+c2相當(dāng)于調(diào)用以下函數(shù):ple*operator+(ple*&c1,ple*&c2){returnple*(c1.real+c2.real,c1.imag+c2.imag);}求出兩個復(fù)數(shù)之和。運行結(jié)果同例10.2。為什么把運算符函數(shù)作為友元函數(shù)呢?因為運算符函數(shù)要訪問ple*類對象中的成員。如果運算符函數(shù)不是ple*類的友元函數(shù),而是一個普通的函數(shù),它是沒有權(quán)利訪問ple*類的私有成員的。在上節(jié)中曾提到過:運算符重載函數(shù)可以是類的成員函數(shù),也可以是類的友元函數(shù),還可以是既非類的成員函數(shù)也不是友元函數(shù)的普通函數(shù)?,F(xiàn)在分別討論這3種情況。首先,只有在極少的情況下才使用既不是類的成員函數(shù)也不是友元函數(shù)的普通函數(shù),原因是上面提到的,普通函數(shù)不能直接訪問類的私有成員。在剩下的兩種方式中,什么時候應(yīng)該用成員函數(shù)方式,什么時候應(yīng)該用友元函數(shù)方式?二者有何區(qū)別呢?如果將運算符重載函數(shù)作為成員函數(shù),它可以通過this指針自由地訪問本類的數(shù)據(jù)成員,因此可以少寫一個函數(shù)的參數(shù)。但必須要求運算表達(dá)式第一個參數(shù)(即運算符左側(cè)的操作數(shù))是一個類對象,而且與運算符函數(shù)的類型相同。因為必須通過類的對象去調(diào)用該類的成員函數(shù),而且只有運算符重載函數(shù)返回值與該對象同類型,運算結(jié)果才有意義。在例10.2中,表達(dá)式c1+c2中第一個參數(shù)c1是ple*類對象,運算符函數(shù)返回值的類型也是ple*,這是正確的。如果c1不是ple*類,它就無法通過隱式this指針訪問ple*類的成員了。如果函數(shù)返回值不是ple*類復(fù)數(shù),顯然這種運算是沒有實際意義的。如想將一個復(fù)數(shù)和一個整數(shù)相加,如c1+i,可以將運算符重載函數(shù)作為成員函數(shù),如下面的形式:ple*ple*∷operator+(int&i)//運算符重載函數(shù)作為ple*類的成員函數(shù){returnple*(real+i,imag);}注意在表達(dá)式中重載的運算符“+”左側(cè)應(yīng)為ple*類的對象,如:c3=c2+i;不能寫成c3=i+c2;//運算符“+”的左側(cè)不是類對象,編譯出錯如果出于*種考慮,要求在使用重載運算符時運算符左側(cè)的操作數(shù)是整型量(如表達(dá)式i+c2,運算符左側(cè)的操作數(shù)i是整數(shù)),這時是無法利用前面定義的重載運算符的,因為無法調(diào)用i.operator+函數(shù)。可想而知,如果運算符左側(cè)的操作數(shù)屬于C++標(biāo)準(zhǔn)類型(如int)或是一個其他類的對象,則運算符重載函數(shù)不能作為成員函數(shù),只能作為非成員函數(shù)。如果函數(shù)需要訪問類的私有成員,則必須聲明為友元函數(shù)??梢栽趐le*類中聲明:friendple*operator+(int&i,ple*&c);//第一個參數(shù)可以不是類對象在類外定義友元函數(shù):ple*operator+(int&i,ple*&c)//運算符重載函數(shù)不是成員函數(shù){returnple*(i+c.real,c.imag);}將雙目運算符重載為友元函數(shù)時,在函數(shù)的形參表列中必須有兩個參數(shù),不能省略,形參的順序任意,不要求第一個參數(shù)必須為類對象。但在使用運算符的表達(dá)式中,要求運算符左側(cè)的操作數(shù)與函數(shù)第一個參數(shù)對應(yīng),運算符右側(cè)的操作數(shù)與函數(shù)的第二個參數(shù)對應(yīng)。如:c3=i+c2;//正確,類型匹配c3=c2+i;//錯誤,類型不匹配請注意,數(shù)學(xué)上的交換律在此不適用。如果希望適用交換律,則應(yīng)再重載一次運算符“+”。如ple*operator+(ple*&c,int&i)//此時第一個參數(shù)為類對象{returnple*(i+c.real,c.imag);}這樣,使用表達(dá)式i+c2和c2+i都合法,編譯系統(tǒng)會根據(jù)表達(dá)式的形式選擇調(diào)用與之匹配的運算符重載函數(shù)??梢詫⒁陨蟽蓚€運算符重載函數(shù)都作為友元函數(shù),也可以將一個運算符重載函數(shù)(運算符左側(cè)為對象名的)作為成員函數(shù),另一個(運算符左側(cè)不是對象名的)作為友元函數(shù)。但不可能將兩個都作為成員函數(shù),原因是顯然的。C++規(guī)定,有的運算符(如賦值運算符、下標(biāo)運算符、函數(shù)調(diào)用運算符)必須定義為類的成員函數(shù),有的運算符則不能定義為類的成員函數(shù)(如流插入“<<”和流提取運算符“>>”、類型轉(zhuǎn)換運算符)。由于友元的使用會破壞類的封裝,因此從原則上說,要盡量將運算符函數(shù)作為成員函數(shù)。但考慮到各方面的因素,一般將單目運算符重載為成員函數(shù),將雙目運算符重載為友元函數(shù)。在學(xué)習(xí)了本章第10.7節(jié)例10.9的討論后,讀者對此會有更深入的認(rèn)識。說明:有的C++編譯系統(tǒng)(如VisualC++6.0)沒有完全實現(xiàn)C++標(biāo)準(zhǔn),它所提供不帶后綴.h的頭文件不支持把成員函數(shù)重載為友元函數(shù)。上面例10.3程序在GCC中能正常運行,而在VisualC++6.0中會編譯出錯。但是VisualC++所提供的老形式的帶后綴.h的頭文件可以支持此項功能,因此可以將程序頭兩行修改如下,即可順利運行:*include<iostream.h>以后如遇到類似情況,亦可照此辦理。//OverLoad.cpp:定義控制臺應(yīng)用程序的入口點。//*include"stdaf*.h"*include<iostream>usingnamespacestd;classple*{public: friendple*operator-(constple*&lhs,constple*&rhs);//非成員函數(shù)友元函數(shù)friendple*operator+(constple*&lhs,constple*&rhs);//非成員函數(shù)友元函數(shù)ple*(constple*&c); ple*(){real=0;imag=0;} constple*&operator=(constple*&c); ple*(doubler,doublei){real=r;imag=i;} ple*operator+(constple*&rhs);//聲明重載運算符的函數(shù)ple*operator+=(constple*&rhs); //ple*operator+(constple*&lhs,constple*&rhs);//error二進(jìn)制“operator*”的參數(shù)太多//重載的函數(shù)為成員函數(shù)的時候this自動綁定到左側(cè)對象參數(shù)數(shù)量少一個booloperator==(constple*&rhs); //booloperator==(constple*&lhs,constple*&rhs);//error二進(jìn)制“operator*”的參數(shù)太多booloperator!=(constple*&rhs); ple*operator*(constple*&rhs); //ple*operator*(constple*&lhs,constple*&rhs);//error二進(jìn)制“operator*”的參數(shù)太多voiddisplay();private: doublereal; doubleimag;};ple*operator-(constple*&lhs,constple*&rhs)//非成員函數(shù)訪問私有變量必須定義為友元函數(shù){ple*result; result.real=lhs.real-rhs.real; result.imag=lhs.imag-rhs.imag; returnresult;}ple*operator+(constple*&lhs,constple*&rhs)//非成員函數(shù)訪問私有變量必須定義為友元函數(shù){ple*result; result.real=lhs.real+rhs.real; result.imag=lhs.imag+rhs.imag; returnresult;}constple*&ple*::operator=(constple*&c){ real=c.real; imag=c.imag; return*this;}ple*::ple*(constple*&c){ real=c.real; imag=c.imag;}ple*ple*::operator*(co

溫馨提示

  • 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

提交評論