白話文說c++ 操作符過載
前言
c++操作符過載的背景主要是原有的操作符+ - += 等只能運算基本資料型別 int double這些,但是實際中我們經常遇到很多自定義的型別,比如複數 結構體等,比如要計算1+2i 與2+3i這兩個複數的和或者比大小,計算機就沒有直接的方法進行計算,這時候,運算子過載起到了很大的作用,其實我們也可以自己定義一個add(complex a,complex b)進行計算,但是通過運算子過載,我們可以利用+號實現add()這個函式功能,類似,我們還可以比較a與b的大小。此外,我們也可以比較兩個結構體的大小,規則由你自己定。
運算子過載可以過載為友元函式或者成員函式,當然一些運算子比如流運算子<< ,>>只能過載為友元,理由可以看看其他大牛的解讀,廢話不多說,直接上例子。
以下是一個複數類
class complex { double re,im; public: complex(); complex(double re,double im); complex(const complex& another); ~complex(); complex operator+(const complex& another); complex& operator+=(const complex& another); bool operator<(const complex& another); friend ostream& operator<<(ostream& os,const complex& a); friend istream& operator>>(istream& in, complex& a); friend complex& operator+(const complex& a,const complex& b); };
我只拿了幾個有代表性的例子
1.complex operator+( complex another);
friend complex& operator+(const complex& a,const complex& b);
這是過載+運算子,第一個是成員函式,第二個是友元函式,可能你們已經看出來了有些是引用,有些不是引用,下面一一討論引數和返回值到底要不要用引用。
引數是否需要引用,說到引用,可以理解為別名,也可以理解為指標常量, complex * const p = &obj,p就是一個指標常量,也就是指標指向的地址是固定的,即使在下一句再寫 p = &obj,也會報錯,引用也一樣,complex& p=obj,p和obj也是繫結在一起的,改變兩者中任一個值,另外一個也會改變,當然,析構任意一個,另外一個也被析構了,並且只調用了解構函式一次,不是兩次。所以引用型變數作為引數時不是進行值傳遞,我覺得便於記憶可以理解為將物件本身傳進去了,而如果不用引用,將會是進行值傳遞,編譯器會自動呼叫拷貝建構函式,建立一個臨時物件,而通過引用型變數將不會呼叫建構函式,更高效。但有一個問題,如果傳引用不小心被改變了怎麼辦呢?我們並不想改變原有物件的值,所以加一個const,防止物件被改變。附上測試圖
int main(int argc, char** argv) {
complex a(1,2),b(3,4);
complex c;
c = a.operator+(b);
cout<<c;
return 0;
}
complex complex::operator+( complex another){
complex res;
res.im = this->im+another.im;
res.re = this->re+another.re;
return res;
}
一共呼叫了5次建構函式分別是建立物件a,b,c,res時和進行值傳遞時呼叫了拷貝建構函式,所以引數採用引用可以更加高效,省去了拷貝構造臨時變數和析構臨時變數的時間,不要忘記加const。
而返回值是否需要引用就是要根據返回的物件是否是在該函式建立的臨時變數,上文說到引用型變數會和其繫結的變數一同析構,如果返回一個臨時變數的引用,而該臨時變數當該函式執行完會被析構,所以返回它的引用自然就是一個垃圾值了,而如果返回的是引數的引用,當該函式執行完時,該引數並不會被析構,所以返回它的引用是沒問題的。當然也可以僅僅返回值,只不過這時又會呼叫拷貝建構函式,效率不高。
complex complex::operator+( const complex& another){
complex res;
res.im = this->im+another.im;
res.re = this->re+another.re;
return res;
}//res是在該函式體內建立的物件,只能返回值,因為離開函式體,res就會被析構,如果返回引用將會是一個垃圾資料
complex& complex::operator+=(const complex& a){
this->im += a.im;
this->re += a.re;
return *this;
}//可以返回引用型,省去了拷貝構造,更加高效 main函式呼叫時可以用a+=b或者a.operator+=(b)呼叫 兩者結果一致
部分原始碼
class complex
{
double re,im;
public:
complex();
complex(double re,double im);
complex(const complex& another);
~complex();
complex operator+( const complex& another);
complex& operator+=(const complex& another);
complex operator-(const complex& another);
complex operator*(const complex& another);
bool operator<(const complex& another);
bool operator>(const complex& another);
friend complex operator-(const complex& a,const complex& b);
friend ostream& operator<<(ostream& os,const complex& a);
friend istream& operator>>(istream& in, complex& a);
friend complex& operator+(const complex& a,const complex& b);
friend complex& operator+=(complex& a,const complex& b);
friend complex operator*(complex& a,const complex&b);
};
complex::complex(){
std::cout<<"complex():"<<endl;
}
complex::complex(double re,double im){
cout<<"complex(re,im):"<<endl;
this->im = im;
this->re = re;
}
complex::~complex(){
cout<<"~complex()"<<endl;
}
complex::complex(const complex& another){
cout<<"copy constructor!"<<endl;
this->im = another.im;
this->re = another.re;
}
//complex operator+(const complex& another);成員函式過載+
complex complex::operator+( const complex &another){
complex res;
res.im = this->im+another.im;
res.re = this->re+another.re;
return res;
}
//friend complex operator+(const complex& a,const complex& b);友元函式過載+
complex& operator+(const complex&a,const complex& b){
complex res;
res.im = a.im+b.im;
res.re = a.re+b.re;
return res;
}
//complex operator-(const complex& another);成員函式過載-
complex complex::operator-(const complex& another){
complex res;
res.im = this->im-another.im;
res.re = this->re-another.re;
return res;
}
//friend complex operator-(const complex& a,const complex& b); 友元函式過載-
complex operator-(const complex& a,const complex& b){
complex res;
res.im = a.im-b.im;
res.re = a.re-b.re;
return res;
}
//friend ostream& operator<<(ostream& os,const complex& a);友元函式過載輸出流
ostream& operator<<(ostream& os,const complex& a){
os<<"("<<a.re<<","<<a.im<<"i)"<<endl;
return os;
}
// friend istream& operator>>(istream& in, complex& a); 友元函式過載輸入流
istream& operator>>(istream& in,complex& a){
in>>a.re>>a.im;
return in;
}
//complex& operator+=(const complex& another); 成員函式過載+=
complex& complex::operator+=(const complex& a){
this->im += a.im;
this->re += a.re;
return *this;
}
//friend complex& operator+=(complex& a,const complex& b);友元函式 過載+=
complex& operator+=(complex& a,const complex& b){
a.im += b.im;
a.re += b.re;
return a;
}
//complex operator*(const complex& another); 成員函式過載*
complex complex::operator*(const complex& another){
complex res;
res.re = this->re*another.re-this->im*another.im;
res.im = this->re*another.im+this->im*another.re;
return res;
}
//friend complex operator*(complex& a,const complex&b); 友元函式過載*
complex operator*(const complex& a,const complex& b){
complex res;
res.re = a.re*b.re-a.im*b.im;
res.im = a.re*b.im+a.im*b.re;
return res;
}
//自定義比較虛數大小
bool complex::operator<(const complex& another){
return this->re>another.re;
}
bool complex::operator>(const complex& another){
return this->re<another.re;
}