一、運算符的重載
1、運算符的重載
允許把標准運算符(如+ - * /等運算符)應用於自定義數據類型的對象,可以提高程序的可讀性,運算符的重載本質上還是函數重載。運算符僅僅是語法上的方便,它是另一種函數調用的方式,只有在設計涉及的代碼更容易寫,尤其是更容易讀的時候才有必要重載。
2、實現運算符重載的方式------既然是操作符重載,就必然會訪問類的私有成員變量,根據類的封裝性要求,除了友元函數外,其他任何外部操作都是違規的,所以不能用普通函數來重載操作符
- 類的成員函數
- 友元函數(即類外的普通函數)
- 普通函數---在極少數的情況下才會使用普通函數,因為普通函數不能直接訪問類的私有成員。解決方法是在類中定義公用的設置數據的set函數和讀取數據的get函數,在重載函數中調用這些函數去訪問類的私有成員。顯然這樣不好。
3、運算符重載的原則:
- 不能重載的運算符有5個: . .* ?: :: sizeof
- 運算符重載不允許發明新的運算符
- 不能改變運算符操作對象的個數
- 運算符被重載后其優先級與結合性不會改變
4、友元函數與類成員函數的使用場合:
- 一般情況下,建議一元運算符使用類的成員函數,二元運算符使用友元函數
- 運算符的操作需要修改類對象的狀態,則使用成員函數。如需要做左值操作數的運算符(=,+=,*=,++,--)
- 運算時,有數與對象的混合運算時,必須使用友元函數
- 二元運算中,第一個操作數為非對象時,必須使用友元函數。如輸入輸出運算符<< >>
- 具體規則如下:

5.友元函數與類成員函數的參數與返回值
- 參數:
- 當參數不會被改變時,一般采用const引用,
- 返回值:
- 如果返回值可能出現在=左邊,則只能作為左值,返回非const引用
- 如果返回值只能出現在=右邊,則只能作為右值,返回const型值或const型引用
- 如果返回值既可能出現在=號左邊,也可能出現在=右邊,則其返回值必須為左值,返回非const引用。
二、使用函數、類成員函數、友元函數分別實現復數+運算符的重載
1、使用函數實現兩個復數相加。示例代碼如下:
-
1 class Complex 2 { 3 public: 4 Complex() 5 { 6 real = 0; 7 imag = 0; 8 } 9 10 Complex Complex_Add(Complex &); 11 12 private: 13 double real; 14 double imag; 15 }; 16 17 Complex Complex :: Complex_Add(Complex &c2) 18 { 19 Complex temp; 20 temp.real = this->real + c2.real; 21 temp.imag = this->imag + c2.imag; 22 23 return temp; 24 } 25 26 int main() 27 { 28 Complex c1(3,4),c2(1.2,-4),c3; 29 c3 = c1.Complex_Add(c2); 30 return 0; 31 }
-
這種調用方式太繁瑣而且不直觀
2、使用類成員函數重載運算符+實現復數運算。具體代碼如下:
-
1 class Complex 2 { 3 public: 4 Complex() //無參構造函數 5 { 6 real = 0; 7 imag = 0; 8 } 9 Complex(double r, double i) //有參構造函數 10 { 11 real = r; 12 imag = i; 13 } 14 Complex operator + (Complex &c2); //聲明重載運算符 15 private: 16 double real; 17 double imag; 18 }; 19 20 Complex Complex::operator +(Complex &c2) 21 { 22 Complex C;//定義一個C對象是為了能夠連續使用+操作符 23 C.real = real + c2.real; 24 C.imag = imag + c2.imag; 25 return C; 26 } 27 int main() 28 { 29 Complex c1(3,4), c2(5,-10), c3; 30 c3 = c1 + c2; //運算符+ 用於復數運算 31 return 0; 32 }
-
主函數在執行c1+c2語句時,調用了運算符重載函數operator+()函數
- 相當於c1.operaor+(c2);
3、使用友元函數重載運算符+實現復數的相加。具體代碼如下:
-
1 class Complex 2 { 3 public: 4 Complex() 5 { 6 real = 0; 7 imag = 0; 8 } 9 Complex(double r, double i) 10 { 11 real = r; 12 imag = i; 13 } 14 friend Complex operator + (Complex &c1, Complex &c2); //聲明重載運算符 15 private: 16 double real; 17 double imag; 18 }; 19 20 Complex operator +(Complex &c1,Complex &c2) 21 { return Complex(c1.real + c2.real, c1.imag + c2.imag);//直接調用復制構造函數 22 } 23 int main() 24 { 25 Complex c1(3,4), c2(5,-10), c3; 26 c3 = c1 + c2; //運算符+ 用於復數運算 27 return 0; 28 }
必須是complex的對象才可以相加。如果是實數與complex對象相加,則實數會被默認的構造函數強制轉換為虛部為0的復數進行相加。
三、成員函數重載與友元函數重載的區別:
1、成員函數與友元函數的區別
- 成員函數:可以通過this指針訪問本類的成員,可以少寫一個參數,但是表達式左邊的的第一個參數必須是類對象,通過該類對象來調用成員函數。即表達式左側的左側運算量就是對象本身。
- 友元函數:左邊一般不是對象。比如輸入輸出運算符<< >>一般都要申明為友元重載函數。
2、成員函數與友元函數對單目運算符雙目運算符的比較
- 對於雙目運算符:成員函數重載運算符參數列表需要含有一個參數,而友元函數重載運算符的參數列表需要有兩個參數,
- 對於單目運算符:成員函數重載運算符的參數列表中沒有參數,而友元函數重載運算符的參數列表中含有一個參數。
- 雙目運算符可以被重載為友元函數運算符和成員函數運算符。對於復數類+號運算符的重載:當一個整數與一個復數相加時必須使用友元函數。因為使用成員函數表達式左側必須是對象本身。因此雙目運算符一般使用友元函數重載,單目運算符一般使用成員函數重載。
- 下邊列舉分別使用成員函數與友元函數重載的++,--,自加加,自減減的例子
- 使用成員函數以前綴和后綴方式重載運算符--;代碼如下:
-
1 class three 2 { 3 public: 4 three(int a=0,int b=0,int c=0); 5 void print(); 6 three operator--();//聲明自減運算符--重載成員函數(前綴方式) 7 three operator--(int);//聲明自減運算符--重載成員函數(后綴方式) 8 private: 9 int x,y,z; 10 }; 11 12 three::three(int a,int b,int c) 13 { 14 x=a; 15 y=b; 16 z=c; 17 } 18 three three::operator--() 19 { 20 --x; 21 --y; 22 --z; 23 return *this;//返回自減后的當前對象 24 } 25 three three::operator--(int) 26 { 27 three temp(*this); 28 x--; 29 y--; 30 z--; 31 return temp; 32 }
-
- 使用友元函數以前綴方式后綴方式重載運算符++。具體代碼如下:
-
1 class three 2 { 3 public: 4 three(int a=0,int b=0,int c=0); 5 void print(); 6 friend three operator++(three &op);//聲明自加運算符++重載友元函數(前綴方式) 7 friend three operator++(three &op,int);//聲明自加運算符++重載友元函數(后綴方式) 8 private: 9 int x,y,z; 10 }; 11 12 three::three(int a,int b,int c) 13 { 14 x=a; 15 y=b; 16 z=c; 17 } 18 19 three operator++(three &op) 20 { 21 ++op.x; 22 ++op.y; 23 ++op.z; 24 return op; 25 } 26 27 three operator++(three &op,int) 28 { 29 op.x++; 30 op.y++; 31 op.z++; 32 return op; 33 }
-
- 使用成員函數以前綴和后綴方式重載運算符--;代碼如下:
四、運算符重載過程中引用於const引用的使用詳見后續博客。
