參考文獻:
《C++程序設計》
推薦轉載博文:https://www.cnblogs.com/xiaokang01/p/9166745.html#_label1
.............................................................................................................................................................................
什么是運算符重載?
運算符重載的本質是一個函數
運算符重載作用:
運算符重載限制:
1) 並不是所有的運算符都可以重載。能夠重載的運算符包括:
+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , ->* -> () [] new new[] delete delete[]
上述運算符中,[]
是下標運算符,()
是函數調用運算符。自增自減運算符的前置和后置形式都可以重載。長度運算符sizeof
、條件運算符: ?
、成員選擇符.
和域解析運算符::
不能被重載。
2) 重載不能改變運算符的優先級和結合性。假設上一節的 complex 類中重載了+
號和*
號,並且 c1、c2、c3、c4 都是 complex 類的對象,那么下面的語句:
c4 = c1 + c2 * c3;
等價於:
c4 = c1 + ( c2 * c3 );
乘法的優先級仍然高於加法,並且它們仍然是二元運算符。
3) 重載不會改變運算符的用法,原有有幾個操作數、操作數在左邊還是在右邊,這些都不會改變。例如~
號右邊只有一個操作數,+
號總是出現在兩個操作數之間,重載后也必須如此。
4) 運算符重載函數不能有默認的參數,否則就改變了運算符操作數的個數,這顯然是錯誤的。
5) 運算符重載函數既可以作為類的成員函數,也可以作為全局函數。
將運算符重載函數作為類的成員函數時,二元運算符的參數只有一個,一元運算符不需要參數。之所以少一個參數,是因為這個參數是隱含的。
例如,上節的 complex 類中重載了加法運算符:
complex operator+(const complex & A) const;
當執行:
c3 = c1 + c2;
會被轉換為:
c3 = c1.operator+(c2);
通過 this 指針隱式的訪問 c1 的成員變量。
將運算符重載函數作為全局函數時,二元操作符就需要兩個參數,一元操作符需要一個參數,而且其中必須有一個參數是對象,好讓編譯器區分這是程序員自定義的運算符,防止程序員修改用於內置類型的運算符的性質。
例如,下面這樣是不對的:
- int operator + (int a,int b){
- return (a-b);
- }
+
號原來是對兩個數相加,現在企圖通過重載使它的作用改為兩個數相減, 如果允許這樣重載的話,那么表達式4+3
的結果是 7 還是 1 呢?顯然,這是絕對禁止的。
如果有兩個參數,這兩個參數可以都是對象,也可以一個是對象,一個是C ++內置類型的數據,例如:
- complex operator+(int a, complex &c){
- return complex(a+c.real, c.imag);
- }
它的作用是使一個整數和一個復數相加。
另外,將運算符重載函數作為全局函數時,一般都需要在類中將該函數聲明為友元函數。原因很簡單,該函數大部分情況下都需要使用類的 private 成員。
上節的最后一個例子中,我們在全局范圍內重載了+
號,並在 complex 類中將運算符重載函數聲明為友元函數,因為該函數使用到了 complex 類的 m_real 和 m_imag 兩個成員變量,它們都是 private 屬性的,默認不能在類的外部訪問。
6) 箭頭運算符->
、下標運算符[ ]
、函數調用運算符( )
、賦值運算符=
只能以成員函數的形式重載。
運算符重載的方法步驟
全局函數、類成員函數方法實現運算符重載步驟
1)要承認操作符重載是一個函數,寫出函數名稱operator+ ()
2)根據操作數,寫出函數參數
3)根據業務,完善函數返回值(看函數是返回引用 還是指針 元素),及實現函數業務
1 #include <iostream> 2 using namespace std; 3 4 class Complax 5 { 6 private: 7 int a; 8 int b; 9 // 重載友元函數 全局函數 操作符重載 10 friend Complax operator+(Complax &c1, Complax &c2); 11 public: 12 Complax(int a = 0, int b = 0) 13 { 14 this->a = a; 15 this->b = b; 16 } 17 void printC() 18 { 19 cout << "a = " << a << "\tb = " << b << endl; 20 } 21 // 2成員函數法 實現 - 運算符重載 22 Complax operator-(Complax &c2) 23 { 24 // this->a -= c2.a; 25 // this->b -= c2.b; 26 // return *this; // 這一個會改變c1的值,因為是+= 27 Complax temp(this->a - c2.a, this->b -c2.b); 28 return temp; 29 30 } 31 32 }; 33 // 1全局函數法 實現 + 運算符重載 34 Complax operator+(Complax &c1, Complax &c2) 35 { 36 Complax temp(c1.a+c2.a, c1.b+c2.b); 37 return temp; 38 } 39 /* 40 全局函數,類成員函數方法實現運算符重載步驟 41 1:要承認運算符重載是一個函數, 寫出函數名稱 42 2: 根據操作數,寫出函數參數 43 3:根據業務,完善函數的返回值(看函數返回引用,元素,指針),及實現函數業務 44 */ 45 int main() 46 { 47 Complax c1(1, 2), c2(3, 4); 48 49 // 1全局函數法 實現 - 運算符重載 50 // Complax operator+(Complax &c1, Complax &c2) 51 Complax c3 = c1 + c2; 52 c3.printC(); 53 54 // 2成員函數法 實現 - 運算符重載 55 // Complax operator-(Complax &c2); 56 Complax c4 = c1 - c2; 57 c4.printC(); 58 59 return 0; 60 } 61 62 運算符重載的兩種方法
++重載例子:
1 #include <iostream> 2 using namespace std; 3 4 class Complax 5 { 6 private: 7 int a; 8 int b; 9 // 1全局函數法 實現 ++ 運算符重載 10 friend Complax& operator++(Complax &c1); // 這里是返回一個引用注意,前置++ 11 friend Complax operator++(Complax &c2, int); // 后置++ 12 13 public: 14 Complax(int a = 0, int b = 0) 15 { 16 this->a = a; 17 this->b = b; 18 } 19 20 // 前置-- 21 // 因為前置返回的是本身,所以返回一個引用 22 // Complax& operator--(Complax &c1) 這個是寫錯的,注意錯在哪里 23 Complax& operator--() 24 { 25 this->a --; 26 this->b --; 27 return *this; 28 } 29 30 // 后置-- 因為后置返回的是一個副本所以不用 返回引用 31 Complax operator--(int) 32 { 33 Complax tem = *this; 34 this->a--; 35 this->b--; 36 return tem; 37 } 38 39 void printC() 40 { 41 cout << "a = " << a << "\tb = " << b << endl; 42 } 43 }; 44 45 46 47 // 特別注意 只有成員函數才有 this指針 48 // 1全局函數法 實現 前置++ 運算符重載 49 Complax& operator++(Complax &c1) 50 { 51 c1.a++; 52 c1.b++; 53 return c1; 54 } 55 // 后置++ 56 Complax operator++(Complax &c2, int) // int防止與前置++重載而加的占位符 57 { 58 // 因為后置++是使用, 在讓c2++所以要定義一個臨時變量 59 Complax tem = c2; 60 c2.a++; 61 c2.b++; 62 return tem; 63 } 64 65 66 int main() 67 { 68 Complax c1(1, 2), c2(30, 40); 69 70 // 1全局函數法 實現 前置++ 運算符重載 71 // Complax& operator++(Complax &c1); 72 ++c1; // 相當於 operator++(c1); 73 c1.printC(); 74 75 // 2成員函數 實現 前置-- 運算符重載 76 // 相當於c2.operator--(); 77 --c2; 78 c2.printC(); 79 80 // 1全局函數法 實現 后置++ 運算符重載 81 // operator++(c2); 82 c2++; 83 // Complax& operator++(Complax &c1); 前置++ 84 // Complax operator++(Complax &c2, int); // int防止與前置++重載而加的占位符 85 c2.printC(); 86 87 // 2成員函數 實現 后置-- 運算符重載 88 // 相當於c2.operator--(); 89 // Complax operator--(int) 函數原型 90 c1--; 91 c1.printC(); 92 93 return 0; 94 } 95 96
深度拷貝:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 using namespace std; 5 6 class Name 7 { 8 public: 9 10 Name (const char *mp) 11 { 12 len = strlen(mp); 13 p = (char *)malloc(sizeof(len+1)); // 注意細節 14 strcpy(p, mp); 15 16 } 17 18 //Name obj2 = obj1; 19 // 解決方案:手工編寫拷貝構造函數,使用深拷貝 20 Name (const Name &obj1) 21 { 22 len = obj1.len; 23 p = (char *)malloc(sizeof(len+1)); 24 strcpy(p, obj1.p); 25 } 26 27 // 成員函數 =運算符重載 不能寫全局函數 28 Name& operator=(const Name &obj) 29 { 30 // 先釋放舊的內存 特別注意 31 if(p != NULL) 32 { 33 delete []p; 34 len = 0; 35 } 36 len = obj.len; 37 p = new char[len+1]; 38 strcpy(p, obj.p); 39 return *this; 40 } 41 ~Name () 42 { 43 cout << "\t析構函數" << endl; 44 if (p != NULL) 45 { 46 free(p); 47 p = NULL; 48 len = 0; 49 } 50 } 51 void printName() 52 { 53 cout <<"\tp = " << this->p << "\t len = " << this->len << endl; 54 } 55 private: 56 char *p; 57 int len; 58 }; 59 60 61 // 對象析構的時候會出現,錯誤 62 // 調試存在bug 63 // 析構的時候會出現二次釋放 64 //默認的拷貝構造函數,如果要對指針進行拷貝,則只是淺拷貝,拷貝過后是兩個變量指向 65 //同一段內存,釋放拷貝的obj2后,obj1的指針就是垃圾值,在釋放就會出錯 66 67 void objmain() 68 { 69 Name obj1("aaaa"); 70 Name obj2 = obj1; 71 Name obj3("sfs"); 72 73 // obj3 = obj1; // 等號操作 c++編譯器會對=進行默認的重載(同樣會發生二次釋放的問題) 74 // 就需要手動的寫 operator= 函數 75 76 cout << "成員函數=重載 "; 77 obj3 = obj1; 78 obj3.printName(); 79 // obj3.operator=(const Name & obj1); 80 // void operator=(const Name &obj) // 函數聲明 81 // 如果要執行 obj3 = obj2 = obj1; 就需要把void 改成 Name& 82 { 83 obj3 = obj2 = obj1; 84 obj3.printName(); 85 obj2.printName(); 86 obj1.printName(); 87 } 88 89 } 90 91 int main04() 92 { 93 objmain(); 94 } 95 96 // 重載 = 運算符注意點 97 // 1 先把舊的內存釋放 98 // 2 返回一個引用 obj3 = obj1 = obj2; 99 // 3數據進行拷貝 100