下面來進行這段代碼的分析:
struct node { //定義一個結構體node(節點)
int x;
int y;
int len; //node中有3個成員變量x,y,len
bool operator <(const node &a)const {//重載<操作符。可以對兩個node使用<操作符進行比較
return len<a.len;
}
};
括號中的const表示參數a對象不會被修改,最后的const表明調用函數對象不會被修改!
想必看到這里對重載運算符算是有一丁點的了解吧,下面看些理論文字,更加清楚的了解關系!
重載運算符的介紹
C++中預定義的運算符的操作對象只能是基本數據類型。但實際上,對於許多用戶自定義類型(例如類),也需要類似的運算操作。這時就必須在C++中重新定義這些運算符,賦予已有運算符新的功能,使它能夠用於特定類型執行特定的操作。運算符重載的實質是函數重載,它提供了C++的可擴展性,也是C++最吸引人的特性之一。
<返回類型說明符> operator <運算符符號>(<參數表>) { <函數體> }
運算符重載時要遵循以下規則:
(1) 除了類屬關系運算符"."、成員指針運算符".*"、作用域運算符"::"、sizeof運算符和三目運算符"?:"以外,C++中的所有運算符都可以重載。 (2) 重載運算符限制在C++語言中已有的運算符范圍內的允許重載的運算符之中,不能創建新的運算符。 (3) 運算符重載實質上是函數重載,因此編譯程序對運算符重載的選擇,遵循函數重載的選擇原則。 (4) 重載之后的運算符不能改變運算符的優先級和結合性,也不能改變運算符操作數的個數及語法結構。 (5) 運算符重載不能改變該運算符用於內部類型對象的含義。它只能和用戶自定義類型的對象一起使用,或者用於用戶自定義類型的對象和內部類型的對象混合使用時。 (6) 運算符重載是針對新類型數據的實際需要對原有運算符進行的適當的改造,重載的功能應當與原有功能相類似,避免沒有目的地使用重載運算符。
成員函數運算符
運算符重載為類的成員函數的一般格式為: <函數類型> operator <運算符>(<參數表>) { <函數體> }
當運算符重載為類的成員函數時,函數的參數個數比原來的操作數要少一個(后置單目運算符除外),這是因為成員函數用this指針隱式地訪問了類的一個對象,它充當了運算符函數最左邊的操作數。因此:
(1) 雙目運算符重載為類的成員函數時,函數只顯式說明一個參數,該形參是運算符的右操作數。 (2) 前置單目運算符重載為類的成員函數時,不需要顯式說明參數,即函數沒有形參。 (3) 后置單目運算符重載為類的成員函數時,函數要帶有一個整型形參。 調用成員函數運算符的格式如下: <對象名>.operator <運算符>(<參數>) 它等價於 <對象名><運算符><參數> 例如:a+b等價於a.operator +(b)。一般情況下,我們采用運算符的習慣表達方式。
友元函數運算符
運算符重載為類的友元函數的一般格式為: friend <函數類型> operator <運算符>(<參數表>) { <函數體> }
當運算符重載為類的友元函數時,由於沒有隱含的this指針,因此操作數的個數沒有變化,所有的操作數都必須通過函數的形參進行傳遞,函數的參數與操作數自左至右一一對應。
調用友元函數運算符的格式如下: operator <運算符>(<參數1>,<參數2>) 它等價於 <參數1><運算符><參數2> 例如:a+b等價於operator +(a,b)。
兩種重載形式的比較
在多數情況下,將運算符重載為類的成員函數和類的友元函數都是可以的。但成員函數運算符與友元函數運算符也具有各自的一些特點:
(1) 一般情況下,單目運算符最好重載為類的成員函數;雙目運算符則最好重載為類的友元函數。 (2) 以下一些雙目運算符不能重載為類的友元函數:=、()、[]、->。 (3) 類型轉換函數只能定義為一個類的成員函數而不能定義為類的友元函數。 (4) 若一個運算符的操作需要修改對象的狀態,選擇重載為成員函數較好。 (5) 若運算符所需的操作數(尤其是第一個操作數)希望有隱式類型轉換,則只能選用友元函數。 (6) 當運算符函數是一個成員函數時,最左邊的操作數(或者只有最左邊的操作數)必須是運算符類的一 個類對象(或者是對該類對象的引用)。如果左邊的操作數必須是一個不同類的對象,或者是一個內部 類型的對象,該運算符函數必須作為一個友元函數來實現。 (7) 當需要重載運算符具有可交換性時,選擇重載為友元函數。
下面具體講講重載運算符的一些具體用法吧!
1.一般運算符重載
在進行對象之間的運算時,程序會調用與運算符相對應的函數進行處理,所以運算符重載有兩種方式:成員函數和友元函數。成員函數的形式比較簡單,就是在類里面定義了一個與操作符相關的函數。友元函數因為沒有this指針,所以形參會多一個。
1 class A 2 { 3 public: 4 A(int d):data(d){} 5 A operator+(A&);//成員函數 6 A operator-(A&); 7 A operator*(A&); 8 A operator/(A&); 9 A operator%(A&); 10 friend A operator+(A&,A&);//友元函數 11 friend A operator-(A&,A&); 12 friend A operator*(A&,A&); 13 friend A operator/(A&,A&); 14 friend A operator%(A&,A&); 15 private: 16 int data; 17 }; 18 //成員函數的形式 19 A A::operator+(A &a) 20 { 21 return A(data+a.data); 22 } 23 A A::operator-(A &a) 24 { 25 return A(data-a.data); 26 } 27 A A::operator*(A &a) 28 { 29 return A(data*a.data); 30 } 31 A A::operator/(A &a) 32 { 33 return A(data/a.data); 34 } 35 A A::operator%(A &a) 36 { 37 return A(data%a.data); 38 } 39 //友元函數的形式 40 A operator+(A &a1,A &a2) 41 { 42 return A(a1.data+a2.data); 43 } 44 A operator-(A &a1,A &a2) 45 { 46 return A(a1.data-a2.data); 47 } 48 A operator*(A &a1,A &a2) 49 { 50 return A(a1.data*a2.data); 51 } 52 A operator/(A &a1,A &a2) 53 { 54 return A(a1.data/a2.data); 55 } 56 A operator%(A &a1,A &a2) 57 { 58 return A(a1.data%a2.data); 59 } 60 //然后我們就可以對類的對象進行+、-、*、/了。 61 void main(void) 62 { 63 A a1(1),a2(2),a3(3); 64 a1=a2+a3; 65 //或者 66 a1=a2.operator+(a3); 67 }
注意:在進行a2+a3的時候會出錯,因為我們在上面對+定義了兩種方法,去掉一種即可。
2.關系運算符重載
因為函數體比較簡單,后面我就只給出成員函數形式的函數聲明了,關系運算符有==,!=,<,>,<=,>=。
1 bool operator == (const A& ); 2 bool operator != (const A& ); 3 bool operator < (const A& ); 4 bool operator <= (const A& ); 5 bool operator > (const A& ); 6 bool operator >= (const A& );
3.邏輯運算符重載
1 bool operator || (const A& ); 2 bool operator && (const A& ); 3 bool operator ! ();
4.單目運算符重載
這里的+、-是正負的意思,放在對象前面。
1 A& operator + (); 2 A& operator - (); 3 A* operator & (); 4 A& operator * ();
5.自增減運算符重載
++和–根據位置的不同有四種情況,都可以重載。
1 A& operator ++ ();//前置++ 2 A operator ++ (int);//后置++ 3 A& operator --();//前置-- 4 A operator -- (int);//后置--
6.位運算符重載
按位操作。
1 A operator | (const A& ); 2 A operator & (const A& ); 3 A operator ^ (const A& ); 4 A operator << (int i); 5 A operator >> (int i); 6 A operator ~ ();
7.賦值運算符重載
沒有=哦。
1 A& operator += (const A& ); 2 A& operator -= (const A& ); 3 A& operator *= (const A& ); 4 A& operator /= (const A& ); 5 A& operator %= (const A& ); 6 A& operator &= (const A& ); 7 A& operator |= (const A& ); 8 A& operator ^= (const A& ); 9 A& operator <<= (int i); 10 A& operator >>= (int i);
8.內存運算符重載
1 void *operator new(size_t size); 2 void *operator new(size_t size, int i); 3 void *operator new[](size_t size); 4 void operator delete(void*p); 5 void operator delete(void*p, int i, int j); 6 void operator delete [](void* p);
9.特殊運算符重載
上面的運算符重載都有兩種方式,而下面的運算符只能用一種,特殊吧。 這些運算符的重載只能是成員函數。
1 A& operator = (const A& ); 2 char operator [] (int i);//返回值不能作為左值 3 const char* operator () (); 4 T operator -> (); 5 //類型轉換符 6 operator char* () const; 7 operator int (); 8 operator const char () const; 9 operator short int () const; 10 operator long long () const; 11 //還有很多就不寫了
而這些只能以友元函數的形式重載
1 friend inline ostream &operator << (ostream&, A&);//輸出流 2 friend inline istream &operator >> (istream&, A&);//輸入流
10.總結
兩種重載方式的比較:
- 一般情況下,單目運算符最好重載為類的成員函數;雙目運算符則最好重載為類的友元函數。
- 以下一些雙目運算符不能重載為類的友元函數:=、()、[]、->。
- 類型轉換函數只能定義為一個類的成員函數而不能定義為類的友元函數。 C++提供4個類型轉換函數:reinterpret_cast(在編譯期間實現轉換)、const_cast(在編譯期間實現轉換)、stactic_cast(在編譯期間實現轉換)、dynamic_cast(在運行期間實現轉換,並可以返回轉換成功與否的標志)。
- 若一個運算符的操作需要修改對象的狀態,選擇重載為成員函數較好。
- 若運算符所需的操作數(尤其是第一個操作數)希望有隱式類型轉換,則只能選用友元函數。
- 當運算符函數是一個成員函數時,最左邊的操作數(或者只有最左邊的操作數)必須是運算符類的一個類對象(或者是對該類對象的引用)。如果左邊的操作數必須是一個不同類的對象,或者是一個內部 類型的對象,該運算符函數必須作為一個友元函數來實現。
- 當需要重載運算符具有可交換性時,選擇重載為友元函數。
注意事項:
- 除了類屬關系運算符”.“、成員指針運算符”.*“、作用域運算符”::“、sizeof運算符和三目運算符”?:“以外,C++中的所有運算符都可以重載。
- 重載運算符限制在C++語言中已有的運算符范圍內的允許重載的運算符之中,不能創建新的運算符。
- 運算符重載實質上是函數重載,因此編譯程序對運算符重載的選擇,遵循函數重載的選擇原則。
- 重載之后的運算符不能改變運算符的優先級和結合性,也不能改變運算符操作數的個數及語法結構。
- 運算符重載不能改變該運算符用於內部類型對象的含義。它只能和用戶自定義類型的對象一起使用,或者用於用戶自定義類型的對象和內部類型的對象混合使用時。
- 運算符重載是針對新類型數據的實際需要對原有運算符進行的適當的改造,重載的功能應當與原有功能相類似,避免沒有目的地使用重載運算符。
