一、什麼是操作符重載
操作符重載可以分為兩部分:“操作符”和“重載”。說到重載想必都不陌生了吧,這是一種編譯時多態,重載實際上可以分為函數重載和操作符重載。運算符重載和函數重載的不同之處在於操作符重載重載的一定是操作符。我們不妨先直觀的看一下所謂的操作符重載:
#include <iostream> using namespace std; int main() { int a = 2 , b = 3; float c = 2.1f , d = 1.2f; cout<<"a + b = "<<a+b<<endl; cout<<"c + d = "<<c+d<<endl; return 0; }
我們看到操作符“+”完成float和int兩種類型的加法計算,這就是操作符重載了。這些內置類型的操作符重載已經實現過了,但是如果現在我們自己寫過的類也要實現實現類似的加法運算,怎麼辦呢??比如現在現在有這樣一個點類point,要實現兩個點的相加,結果是橫縱坐標都要相加,這時候就需要我們自己寫一個操作符重載函數了。
#include <iostream> using namespace std; class point { double x; double y; public: double get_x() { return x; } double get_y() { return y; } point(double X = 0.0 , double Y = 0.0):x(X),y(Y){}; point operator +(point p); }; //重載操作符“+” point point::operator +(point p) { double x = this->x + p.x; double y = this->y + p.y; point tmp_p(x,y); return tmp_p; } int main() { point p1(1.2,3.1); point p2(1.1,3.2); point p3 = p1+p2; cout<<p3.get_x()<<" "<<p3.get_y()<<endl; return 0; }
二、實現操作符重載的兩種方式
操作符重載的實現方式有兩種,即通過“友元函數”或者“類成員函數”。
1.友元函數重載操作符的格式:
class 類名 { friend 返回類型 operator 操作符(形參表); }; //類外定義格式: 返回類型 operator操作符(參數表) { //函數體 }
2.類成員函數實現操作符重載的格式:
class 類名 { public: 返回類型 operator 操作符(形參表); }; //類外定義格式 返回類型 類名::operator 操作符(形參表) { //函數體 }
這樣說吧,還是不足以比較這兩種實現方式的區別,我們分別用兩種實現方式寫point類的”+“和”-“的重載。代碼如下:
#include <iostream> using std::endl; using std::cout; class point { double x; double y; public: double get_x() { return x; } double get_y() { return y; } point(double X = 0.0 , double Y = 0.0):x(X),y(Y){}; friend point operator -(point p1,point p2); point operator +(point p); }; //重載操作符“-” point operator -(point p1,point p2) { double x = p1.get_x() - p2.get_x(); double y = p1.get_y() - p2.get_y(); point p3(x,y); return p3; } //重載操作符“+” point point::operator +(point p) { double x = this->x + p.x; double y = this->y + p.y; point tmp_p(x,y); return tmp_p; } int main() { point p1(1.2,3.2); point p2(1.1,3.1); point p3 = p1+p2; point p4 = operator-(p1,p2); cout<<p3.get_x()<<" "<<p3.get_y()<<endl; cout<<p4.get_x()<<" "<<p4.get_y()<<endl; return 0; }
這裡不知道大家看到沒有,利用友元函數重載二元操作符”-“時,形式參數是兩個,而利用類成員函數時,形式參數卻只有一個。這時因為類成員函數中存在this指針,這相當於一個參數,所以類成員實現操作符重載需要的形式參數比原來少一個,這比如:利用類成員函數實現一元操作符”-“,就不需要參數了。也正是因為這個原因,友元函數實現的操作符重載是有限制的,比如:[] ,(),->和 =不能利用友元函數實現運算符的重載。
在實際開發過程中,單目運算符建議重載為成員函數,而雙目運算符建議重載為友元函數。通常下雙目運算符重載為友元函數比重載為成員函數更方便,但是有時雙目運算符必須重載為成員函數,例如賦值運算符=。還有如果需要修改對象內部的狀態,一般可以選擇利用類成員函數進行修改。
三、運算符重載的原則
這樣一看,運算符重載還是蠻簡單的嘛,實際上運算符重載也是要遵循一些原則的:
1.C++中只能對已有的C++運算符進行重載,不允許用戶自己定義新的運算符。
2.C++中絕大部分的運算符可重載,除了成員訪問運算符.,作用域運算符::,長度運算符sizeof以及條件運算符?:。
3.運算符重載後不能改變運算符的操作對象(操作數)的個數。如:"+"是實現兩個操作數的運算符,重載後仍然為雙目運算符。
4.重載不能改變運算符原有的優先級和原有的結合性。
6.運算符重載不能全部是C++中預定義的基本數據,這樣做的目的是為了防止用戶修改用於基本類型數據的運算符性質。
四、為什麼要進行運算符重載
關於運算符重載要遵循這麼多原則,那麼為什麼還要進行運算符重載呢?為什麼我不是寫一個add()函數,代替operator +()呢??個人感覺C++中之所以要支持運算符的重載是為了與內置數據類型統一操作,比如:c = a + b 和 c = add(a,b),這看起來哪個更直觀一點呢,顯然是前者了。同時,我們希望操作我們自己定義的數據類型能像操作int和double這些內置數據類型一樣方便。可能舉這個加法的例子有點不好,現在加入重載的運算符是[],<<,^,|等呢?這時我們要用什麼成員函數代替呢??代替之後又是一種什麼效果呢?會一眼就看出來這個函數要干什麼嗎??
思考:C++中的++運算符是有兩種的,這個我們怎麼區別重載的是前自增還是後自增呢?