第五節 操作符重載與臨時對象
今天來分析一下操作符重載。
操作符的重載根據是否為類成員函數分為兩種,在分析時會涉及到一個新的知識點:臨時對象(temp object),語法是typename(),有效域為一行。
我們來看一下第一種操作符重載,在類中進行重載(+=)。
#include<iostream>
using namespace std;
class complex
{
private:
double re,im;
friend complex& _doapl(complex*,const complex&);//為重載時需要調用的函數開一個后門
public:
complex(double r=0,double i=0):re(r),im(i)//構造函數,對re,im進行初始化
{}
complex& operator +=(const complex&);//重載函數
double real() const{return re;}//get re
double image() const{return im;}//get im
};
inline complex& //申請內聯函數(與編譯器相關)
complex::operator +=(const complex& r)//傳入右值
{
return _doapl(this,r);//調用_doapl(do assignment plus),this指向c2
}
inline complex&//返回*ths的引用
_doapl(complex* ths,const complex& r)//+=新算法(重載實現)
{
ths->re+=r.re;
ths->im+=r.im;
return *ths; //返回ths指針指向的變量,即c2
}
int main()
{
complex c1(2,1);
complex c2(5);
c2+=c1;
cout<<"("<<c2.real()<<","<<c2.image()<<")"<<endl;//打印結果
return 0;
}
附一張運行結果:
下面來看第二種操作符重載,在類外進行重載(+,無this)。
根據不同類型的加法運算多次重載'+'運算符。
#include<iostream>
using namespace std;
class complex
{
private:
double re,im;
public:
complex(double r=0,double i=0):re(r),im(i)
{}
double real() const{return re;}//get re
double image() const{return im;}//get im
};
inline complex//因為返回臨時object所以用value而不是reference
operator + (const complex& x,const complex& y)
{
return complex(x.real()+y.real(),x.image()+y.image());
}//對應c2=c1+c2
inline complex
operator + (const complex& x,double y)
{
return complex(x.real()+y,x.image());
}//對應c2=c1+5
inline complex
operator + (double x ,const complex& y)
{
return complex(x+y.real(),y.image());
}//對應c2=7+c1
int main()
{
complex c1(2,1);
complex c2(5);
c2=c1+c2;
//c2=c1+5;
//c2=7+c1;
cout<<"("<<c2.real()<<","<<c2.image()<<")"<<endl;
return 0;
}
附上一張運行結果:
在眾多操作符中,有一種比較特殊,就是'<<'。在對'<<'操作符進行重載時,只能通過
第二種方法,即在全局下重載,下面我們來看一下它的實現。
#include<iostream>
using namespace std;
class complex
{
private:
double re,im;
public:
complex(double r=0,double i=0):re(r),im(i)
{}
double real() const{return re;}
double image() const{return im;}
};
inline ostream&
operator <<(ostream& os,const complex& r)
{
return os<<'('<<r.real()<<','<<r.image()<<')';
}
int main()
{
complex c1(2,1);
cout<<c1<<endl;
return 0;
}
這里簡單的對操作符'<<'進行了重載,使其可是輸入復數。那么請思考一下,既然在operator <<(ostream& os,const complex& r)函數我們已經更改了os,為什么還要return呢?
下面我們對代碼稍作更改。
#include<iostream>
using namespace std;
class complex
{
private:
double re,im;
public:
complex(double r=0,double i=0):re(r),im(i)
{}
double real() const{return re;}
double image() const{return im;}
};
void operator <<(ostream& os,const complex& r)//將返回類型更改為void
{
os<<'('<<r.real()<<','<<r.image()<<')';//去掉了return
}
int main()
{
complex c1(2,1);
cout<<c1;//輸出c1
return 0;
}
運行結果:
既然結果相同,為什么不使用更易理解、使用沒有返回值的方法呢?其實不然,這種方法有它的弊端,比如我們將主函數中的cout<<c1換成cout<<c1<<endl,那么在編譯時就會報錯。原因是操作符'<<'將左值cout與右值c1傳入重載函數后會返回void類型,這時表達式變成了void()<<endl,操作符'<<'的左值應該是ostream類型而非void類型,所以會報錯。為了適應我們一貫的書寫習慣,建議使用返回ostream類型的方法。
今天就到這吧,內容有點多,還有待消化。