例10.2中對運算子「+」進行了過載,使之能用於兩個複數的相加。在該例中運算子過載函式operator+作為complex類中的成員函式。
可能有的讀者會提出這樣的問題:」+「是雙目運算子,為什麼在例10.2程式中的過載函式中只有乙個引數呢?實際上,運算子過載函式有兩個引數,由於過載函式是complex類中的成員函式,有乙個引數是隱含的,運算子函式是用this指標隱式地訪問類物件的成員。可以看到,過載函式operator+訪問了兩個物件中的成員,乙個是this指標指向的物件中的成員,乙個是形參物件中的成員。如this->real+c2.real,this->real就是c1.real。上節中已說明,在將運算子函式過載為成員函式後,如果出現含該運算子的表示式,如c1+c2,編譯系統把它解釋為:
c1.operator+(c2)
即通過物件c1呼叫運算子過載函式,並以表示式中第二個引數(運算子右側的類物件c2)作為函式實參。運算子過載函式的返回值是complex型別,返回值是複數c1和c2之和(complex(c1.real + c2.real, c1.imag+c2.imag))。
運算子過載函式除了可以作為類的成員函式外,還可以是非成員函式。可以將例10.2改寫為例10.3。
[例10.3] 將運算子「+」過載為適用於複數加法,過載函式不作為成員函式,而放在類外,作為complex類的友元函式。
#include
using
namespace std;
// 注意,該程式在vc 6.0中編譯出錯,將以上兩行替換為 #include 即可順利通過
class
complex
complex
(double r,
double i)
friend
complex
operator+(
complex
&c1,
complex
&c2);
//過載函式作為友元函式
void
display();
private
:double real;
double imag;};
complex
operator+(
complex
&c1,
complex
&c2)
//定義作為友元函式的過載函式
void complex::
display()
intmain()
與例10.2相比較,只作了一處改動,將運算子函式不作為成員函式,而把它放在類外,在complex類中宣告它為友元函式。同時將運算子函式改為有兩個引數。在將運算子「+」過載為非成員函式後,c++編譯系統將程式中的表示式c1+c2解釋為
operator+(c1, c2)
即執行c1+c2相當於呼叫以下函式:
complex operator + (complex &c1,complex &c2)
求出兩個複數之和。執行結果同例10.2。
為什麼把運算子函式作為友元函式呢?因為運算子函式要訪問complex類物件中的成員。如果運算子函式不是complex類的友元函式,而是乙個普通的函式,它是沒有權利訪問complex類的私有成員的。
在上節中曾提到過:運算子過載函式可以是類的成員函式,也可以是類的友元函式,還可以是既非類的成員函式也不是友元函式的普通函式。現在分別討論這3種情況。
首先,只有在極少的情況下才使用既不是類的成員函式也不是友元函式的普通函式,原因是上面提到的,普通函式不能直接訪問類的私有成員。
在剩下的兩種方式中,什麼時候應該用成員函式方式,什麼時候應該用友元函式方式?二者有何區別呢?如果將運算子過載函式作為成員函式,它可以通過this指標自由地訪問本類的資料成員,因此可以少寫乙個函式的引數。但必須要求運算表示式第乙個引數(即運算子左側的運算元)是乙個類物件,而且與運算子函式的型別相同。因為必須通過類的物件去呼叫該類的成員函式,而且只有運算子過載函式返回值與該物件同型別,運算結果才有意義。在例10.2中,表示式c1+c2中第乙個引數c1是complex類物件,運算子函式返回值的型別也是complex,這是正確的。如果c1不是complex類,它就無法通過隱式this指標訪問complex類的成員了。如果函式返回值不是complex類複數,顯然這種運算是沒有實際意義的。
如想將乙個複數和乙個整數相加,如c1+i,可以將運算子過載函式作為成員函式,如下面的形式:
complex complex∷operator+(int &i) //運算子過載函式作為complex類的成員函式
注意在表示式中過載的運算子「+」左側應為complex類的物件,如:
c3=c2+i;
不能寫成
c3=i+c2; //運算子「+」的左側不是類物件,編譯出錯
如果出於某種考慮,要求在使用過載運算子時運算子左側的運算元是整型量(如表示式i+c2,運算子左側的運算元i是整數),這時是無法利用前面定義的過載運算子的,因為無法呼叫i.operator+函式。可想而知,如果運算子左側的運算元屬於c++標準型別(如int)或是乙個其他類的物件,則運算子過載函式不能作為成員函式,只能作為非成員函式。如果函式需要訪問類的私有成員,則必須宣告為友元函式。可以在complex類中宣告:
friend complex operator+(int &i,complex &c); //第乙個引數可以不是類物件
在類外定義友元函式:
complex operator+(int &i, complex &c) //運算子過載函式不是成員函式
將雙目運算子過載為友元函式時,在函式的形參表列中必須有兩個引數,不能省略,形參的順序任意,不要求第乙個引數必須為類物件。但在使用運算子的表示式中,要求運算子左側的運算元與函式第乙個引數對應,運算子右側的運算元與函式的第二個引數對應。如:
c3=i+c2; //正確,型別匹配
c3=c2+i; //錯誤,型別不匹配
請注意,數學上的交換律在此不適用。
如果希望適用交換律,則應再過載一次運算子「+」。如
complex operator+(complex &c, int &i) //此時第乙個引數為類物件
這樣,使用表示式i+c2和c2+i都合法,編譯系統會根據表示式的形式選擇呼叫與之匹配的運算子過載函式。可以將以上兩個運算子過載函式都作為友元函式,也可以將乙個運算子過載函式(運算子左側為物件名的) 作為成員函式,另乙個(運算子左側不是物件名的)作為友元函式。但不可能將兩個都作為成員函式,原因是顯然的。
c++規定,有的運算子(如賦值運算子、下標運算子、函式呼叫運算子)必須定義為類的成員函式,有的運算子則不能定義為類的成員函式(如流插入「<<」和流提取運算子「>>」、型別轉換運算子)。
由於友元的使用會破壞類的封裝,因此從原則上說,要盡量將運算子函式作為成員函式。
但考慮到各方面的因素,一般將單目運算子過載為成員函式,將雙目運算子過載為友元函式。
在學習了本章第10.7節例10.9的討論後,讀者對此會有更深入的認識。
說明:有的c++編譯系統(如visual c++ 6.0)沒有完全實現c++標準,它所提供不帶字尾.h的標頭檔案不支援把成員函式過載為友元函式。
上面例10.3程式在gcc中能正常執行,而在visual c++ 6.0中會編譯出錯。但是visual c++所提供的老形式的帶字尾.h的標頭檔案可以支援此項功能,因此可以將程式頭兩行修改如下,即可順利執行:
#include
以後如遇到類似情況,亦可照此辦理。
C 運算子過載函式之成員運算子過載函式
5.2.3 成員運算子過載函式 在c 中可以把運算子過載函式定義為某個類的成員函式,稱之為成員運算子過載函式。1.定義成員運算子過載函式的語法形式 1 在類的內部,定義成員運算子過載函式的格式如下 函式型別 operator 運算子 形參表 2 成員運算子過載函式也可以在類中宣告成員函式的原型,在類...
運算子過載函式作為類成員函式和友元函式
運算子過載函式既可以做為類成員函式也可以過載為友元函式,但使用定義方法和使用上是由較大差別的。首先看乙個運算子過載函式作為類成員函式的示例 定義complex為複數類,過載運算子 實現複數的相加。程式1.1 include using namespace std class complex comp...
運算子過載 成員函式
檔名稱 test.cpp 完成日期 2016年5月14日 問題描述 請用類的成員函式,定義複數類過載運算子 使之能用於複數的加減乘 include using namespace std class complex complex double r,double i complex operator...