運算子過載(函式過載)是c++多型的重要實現手段之一。通過運算子過載對運算子功能進行特殊定製,使其支援特定型別物件的運算,執行特定的功能,增強c++的擴充套件功能。
(1)不可臆造運算子。
(2)運算子原有運算元的個數、優先順序和結合性不能改變。
(3)運算元中至少乙個是自定義型別。
(4)保持過載運算子的自然含義。
一般來說,c++運算子過載可採用成員函式和友元函式,二者都可以訪問類的私有成員,至於該採用哪一種呢,首先看一下二者的區別。
(1)當過載為成員函式時,會隱含乙個this指標;當過載為友元函式時,不存在隱含的this指標,需要在引數列表中顯示地新增運算元。
(2)當過載為成員函式時,只允許右引數的隱式轉換;當過載為友元函式時,能夠接受左引數和右引數的隱式轉換。
class cstring
;
因為cstring的構造函式引數為乙個char*,所以如果採用友元形式的operator +(const cstring&, const cstring&),那麼char+cstring和cstring+char都能正常工作;而如果採用成員函式形式cstring::operator+(const cstring& rhs),則只能接受cstring+char,如果執行char+cstring則會編譯出錯。我們往往習慣cstring+char和char+cstring都應該被接受。需要注意的是,隱式轉換由於臨時變數的增加往往效率不高。如果應用程式對效率要求較高,針對以上類,建議選擇定義多個運算子的友元過載版本:
cstring& operator +(const cstring&, const cstring&);
cstring& operator +(const char*, const cstring&);
cstring& operator +(const cstring&, const char*);
(1)一般而言,對於雙目運算子,最好將其過載為友元函式;而對於單目運算子,則最好過載為成員函式。
但是也存在例外情況。有些雙目運算子是不能過載為友元函式的,比如賦值運算子=、函式呼叫運算子()、下標運算子、指標運算子->等,因為這些運算子在語義上與this都有太多的關聯。比如=表示「將自身賦值為…」,表示「自己的第幾個元素」,如果將其過載為友元函式,則會出現語義上的不一致。
(2)還有乙個需要特別說明的就是輸出運算子<<。因為《的第乙個運算元一定是ostream型別,所以《只能過載為友元函式,如下:
friend ostream& operator <<(ostream& os, const complex& c);
ostream& operator <<(ostream& os, const complex& c)
(3)所以,對於 =、、()、->以及所有的型別轉換運算子只能作為非靜態成員函式過載。如果允許第一運算元不是同類物件,而是其他資料型別,則只能作為非成員函式過載(如輸入輸出流運算子》和《就是這樣的情況)。
過載為類的非成員函式的時候,通常我們都將其宣告為友元函式,因為大多數時候過載運算子要訪問類的私有資料,(當然也可以設定為非友元非類的成員函式,但是非友元又不是類的成員函式是沒有辦法直接訪問類的私有資料的),如果不宣告為類的友元函式,而是通過在此函式中呼叫類的公有函式來訪問私有資料會降低效能。所以一般都會設定為類的友元函式,這樣我們就可以在此非成員函式中訪問類中的資料了。
(4)總結
一般情況下,將雙目運算子過載為友元函式,這樣就可以使用交換律,比較方便。單目運算子一般過載為成員函式,因為直接對類物件本身進行操作。
總之,如果運算子過載為成員函式,第乙個引數必須是本類的物件,因為預設使用第乙個引數的物件進行呼叫該成員函式。
過載的操作符在類體中被宣告,宣告方式如同普通成員函式一樣,只不過他的名字包含關鍵字operator,以及緊跟其後的乙個c++預定義的操作符。
(1)可以用如下的方式來宣告乙個預定義的==操作符:
#includeusing namespace std;
class person
inline bool operator == ( const person &ps ) const;
};bool person::operator==(const person &ps) const
return false;}
int main()
person( person& ps )
};bool operator==( person& p1, person const & p2 ) // 全域性過載操作符==
return false;
}int main()
cout << "not equal " << endl;
return 0;
}
(1)需要返回結果的過載操作符首先要確定它的返回值是左值,還是右值,如果是左值最好返回引用,如果是右值那就直接返回值。
(2)+號等這樣的操作符沒有物件可以容納改變後值,對於這樣的情況最好返回數值,否則只能要操作符體內置立臨時物件用於容納改變後的值,如果在堆中建立臨時物件返回指標或者引用,在操作符函式體外還需要釋放它,如果返回的物件而不是引用或者指標,那麼效率是比較低的。如果返回的是數值,最好在該類的建構函式中增加對該型別數值的轉換函式,如:返回值是int型別,那麼最好有乙個int型別作為引數的建構函式。
(3)在增量運算子中,放上乙個整數形參,就是後增量執行符,它是值返回,對於前增量沒有形參,而且是引用返回。
class test
test& operator++(); // 前增量
test operator++(int); // 後增量
private:
int m_value;
};test& test::operator++()
test test::operator++(int)
(4)因為強制轉換是針對基本資料型別的,所以對類型別的轉換需自定義。
(5)轉換執行符過載宣告形式:operator 型別名();它沒有返回型別,因為型別名就代表了它的返回型別,所以返回型別顯得多餘。
(6)一般來說,轉換運算子與轉換建構函式(即帶乙個引數的建構函式)是互逆的,如有了建構函式test(int),那麼最好有乙個轉換運算子int()。這樣就不必提供物件引數過載運算子了,如test a1(1);test a2(2); test a3; a3 = a1+a2;就不需要過載+號操作符了,因為對於a1+a2的運算,系統可能會先找有沒有定義針對test的+號操作符,如果沒有,它就會找有沒有針對test類轉換函式引數型別的+號操作符(因為可以將+號執行結果的型別通過轉換函式轉換為test物件),因為test類有個int型別的引數,對於int型別有+操作符,所以a1+a2真正執行的是test(int(a1) + int(a2));即test(3);
(7)對於轉換運算子,還有乙個需要注意的地方就是,如果a類中有以b為引數的轉換函式(建構函式),那b中不能有a的轉換運算子,不然就存在轉換的二義性,如:
class a}; class b}; // 那麼以下語句就會有問題:
b b; a(b); // a(b) 就可能是a的建構函式,也可以是b的轉換運算子
運算子過載的注意事項
在 c 中進行運算子過載時的注意事項 c 規定,運算子過載不改變運算子的優先順序。以下運算子不能被過載 sizeof 過載運算子 賦值運算子 和型別強制轉換運算子 時,只能將它們過載為成員函式,不能過載為全域性函式。必要時需要過載賦值運算子 即進行深拷貝,以避免兩個物件內部的指標指向同一片儲存空間。...
C 運算子過載的注意事項
1 過載操作符沒必要一定是成員函式,還可以是友元函式。2 過載操作符函式為成員函式主要是你需要操作類內部的成員,必須是成員函式或友元函式才行。3 至於由深淺拷貝的原因要使其成為成員函式,這個不知道。4 如果運算子被過載為全域性函式,那麼只有乙個引數的運算子叫做一元運算子,有兩個引數的運算子叫做二元運...
過載運算子
題目描述 定義乙個矩形類,資料成員包括左下角和右上角座標,定義的成員函式包括必要的建構函式 輸入座標的函式,實現矩形加法,以及計算並輸出矩形面積的函式。要求使用提示中給出的測試函式並不得改動。兩個矩形相加的規則是 決定矩形的對應座標分別相加,如 左下角 1,2 右上角 3,4 的矩形,與 左下角 2...