標籤:c++ 操作符 運算子 重載
第四章 運算子多載
4.1 運算子多載的基本概念1. 運算子2. 自訂資料類型與運算子多載
C++提供了資料抽象的手段:使用者自己定義資料類型 -- 類
? 調用類的成員函數—>操作它的對象
類的成員函數—>操作對象時,很不方便
? 在數學上,兩個複數可以直接進行+/-等運算 Vs. 在C++中,直接將+或-用於複數是不允許的
3. 運算子多載
- 對抽象資料類型也能夠直接使用C++提供的運算子
? 程式更簡潔
? 代碼更容易理解
- 運算子多載
? 對已有的運算子賦予多重的含義
? 使同一運算子作用於不同類型的資料時—>不同類型的行為
- 目的
? 擴充C++中提供的運算子的適用範圍,以用於類所表示的抽象資料類型
- 同一個運算子,對不同類型的運算元,所發生的行為不同
? (5,10i) + (4,8i) = (9,18i)
? 5 + 4 = 9
- 運算子多載的實質是函數重載
返回值類型 operator 運算子(形參表)
{
……
}
- 在程式編譯時間:
? 把含 運算子的運算式 —> 對 運算子函數 的調用
? 把 運算子的運算元 —> 運算子函數的 參數
? 運算子被多次重載時, 根據 實參的類型 決定調用哪個運算子函數
? 運算子可以被重載成普通函數
? 也可以被重載成類的成員函數
4. 運算子多載為普通函數
class Complex { public: Complex( double r = 0.0, double i= 0.0 ){ real = r; imaginary = i; } double real; // real part double imaginary; // imaginary part};Complex operator+ (const Complex & a, const Complex & b){ return Complex( a.real+b.real, a.imaginary+b.imaginary);} // “類名(參數表)” 就代表一個對象Complex a(1,2), b(2,3), c;c = a + b;// 相當於什麼? operator+(a,b)重載為普通函數時,參數個數為運算子目數
5. 運算子多載為成員函數
class Complex { public: Complex( double r= 0.0, double m = 0.0 ):real(r), imaginary(m) { } // constructor Complex operator+ ( const Complex & ); // addition Complex operator- ( const Complex & ); // subtraction private: double real; // real part double imaginary; // imaginary part};// Overloaded addition operatorComplex Complex::operator+(const Complex & operand2) { return Complex( real + operand2.real,imaginary + operand2.imaginary );}// Overloaded subtraction operatorComplex Complex::operator- (const Complex & operand2){ return Complex( real - operand2.real,imaginary - operand2.imaginary );}int main(){ Complex x, y(4.3, 8.2), z(3.3, 1.1); x = y + z;// 相當於什麼? y.operator+(z) x = y - z;// 相當於什麼? y.operator-(z) return 0;}重載為成員函數時,參數個數為運算子目數減一
4.2 賦值運算子的重載1. 賦值運算子 ‘=’ 重載賦值運算子 兩邊的類型 可以 不匹配
? 把一個 int類型變數 賦值給一個 Complex對象
? 把一個 char * 類型的字串 賦值給一個 字串對象
需要 重載賦值運算子 ‘=’
賦值運算子 “=” 只能重載為 成員函數
編寫一個長度可變的字串類String
? 包含一個char * 類型的成員變數
—> 指向動態分配的儲存空間
? 該儲存空間用於存放 ‘\0’ 結尾的字串
class String { private: char * str; public: String () : str(NULL) { } //建構函式, 初始化str為NULL const char * c_str() { return str; } //傳回值為const類型,保證str不會被修改。比如char* p=str.c_str();則編譯器會報錯,類型不符。 char * operator = (const char * s); ~String( );//需要考慮String對象是否指向了動態分配的儲存空間}; //重載‘=’使得obj = “hello”能夠成立char * String::operator = (const char * s){ if(str) delete [] str; if(s) { //s不為NULL才會執行拷貝 str = new char[strlen(s)+1]; strcpy(str, s); } else str = NULL; return str;}String::~String( ) { if(str) delete [] str;};int main(){ String s; s = “Good Luck,” ; cout << s.c_str() << endl; // String s2 = “hello!”; //這條語句要是不注釋掉就會出錯 s = "Shenzhou 8!"; cout << s.c_str() << endl; return 0;}2. 重載賦值運算子的意義 – 淺複製和深複製
S1 = S2;
S1和S2指向了同一塊動態分配記憶體地區,那麼當S1和S2同時消亡的時候,這一塊記憶體空間就會被先後釋放兩次。這樣就會導致嚴重的記憶體錯誤,甚至可能引發程式意外的中止。
所以我們看到,這樣的一個淺拷貝,或者淺複製的工作本身並不能實現我們所希望實現的像S2中間的這個str字串複製給S1本身指向的那一塊空間。
- 深複製/深拷貝
將一個對象中指標變數指向的內容 —> 複製到另一個對象中指標成員對象指向的地方
在 class MyString 裡新增成員函數:
String & operator = (const String & s) { if(str) delete [] str; str = new char[strlen(s.str)+1]; strcpy(str, s.str); return * this;}
3. 思考
考慮下面語句,是否會有問題?
MyString s; s = “Hello”; s = s;
正確寫法:
String & String::operator = (const String & s){ if(str == s.str) return * this;//增加此行 if(str) delete [] str; if(s.str) { //s.str不為NULL才會執行拷貝 str = new char[strlen(s.str)+1]; strcpy( str,s.str); } else str = NULL; return * this;}
4. 對 operator = 返回值類型的討論
- void 好不好?
考慮: a = b = c;
//等價於a.operator=(b.operator=(c));
- String 好不好?為什麼是 String &
運算子多載時, 好的風格 -- 盡量保留運算子原本的特性
考慮: (a=b)=c; //會修改a的值
分別等價於:(a.operator=(b)).operator=(c);
5. 上面的String類是否就沒有問題了?
為 String類編寫 複製建構函式 時,會面臨和 ‘=’ 同樣的問題,用同樣的方法處理
String::String(String & s){ if(s.str) { str = new char[strlen(s.str)+1]; strcpy(str, s.str); } else str = NULL;}
4.3 運算子多載為友元函數1. 運算子多載為友元
- 通常,將運算子多載為類的成員函數
- 重載為友元函數的情況:
? 成員函數不能滿足使用要求
? 普通函數,又不能訪問類的私人成員
class Complex{ double real, imag; public: Complex(double r, double i):real(r), imag(i){ }; Complex operator+(double r);};Complex Complex::operator+(double r){ //能解釋 c+5 return Complex(real + r, imag);}經過上述重載後:
Complex c ;
c = c + 5; //有定義,相當於 c = c.operator +(5);
但是:
c = 5 + c; //編譯出錯
為了使得上述運算式能成立, 需要將+重載為普通函數
Complex operator+ (double r, const Complex & c) { //能解釋 5+c return Complex( c.real + r, c.imag);}普通函數不能訪問私人成員 —> 將運算子+重載為友元函數
class Complex { double real, imag; public: Complex( double r, double i):real(r),imag(i){ }; Complex operator+( double r ); friend Complex operator + (double r, const Complex & c);};
PKU C++程式設計實習 學習筆記4 運算子多載