C++運算符重載,友元

在介紹運算符重載之前,先看一下下面的代碼,在實際編程中,我們一般如果要將兩個數組相加,一般都會採用如下for循環的形式進行實現:

for(int i=0;i<20;i++)
{
everning[i]=sam[i]+janet[i];//遍歷每個元素,然後將每個元素進行相加
}

,這樣是不是顯得有點冗餘,複雜,尤其是如果存在類對象需要相加,而且類中的成員變量又比較多的話,那就需要寫很多條語句,顯得很麻煩。但在C++中,可以定義一個表示數組的類,並使用重載+運算符,於是便可以有這樣的語句:

everning=sam+janet;

理論的知識這裏不講,實例最具有說服力,最能讓人理解運算符重載到底是什麼。下面是c++ primer plus上的一個例子。

頭文件:

#ifndef OPERATOR_LOADING_H_
#define OPERATOR_LOADING_H_
#include<iostream>
class Time
{
private:
	int mins;
	int hours;
public:
	Time(){ mins = 0; hours = 0; };
	Time(int hour, int min){ mins = min, hours = hour; };
	void AddMin(int m);
	void AddHours(int h);
	void Reset(int m, int h){ mins = m; hours = h; };
	Time operator+(const Time& s) const;//加法重載
	Time operator-(const Time& s) const;//減法重載
	Time operator*(double t) const;//乘法重載
	friend Time operator*(double m, const Time& T);//友元重載
	friend std::ostream & operator<<(std::ostream & os, const Time &t);//友元重載
protected:

};
#endif

源文件:

#include"operater_overloading.h"
void Time::AddMin(int m)
{
	mins += m;
}

void Time::AddHours(int h)
{
	hours += h;
}
Time Time::operator+(const Time& s) const
{
	Time sum;
	sum.mins = mins + s.mins;
	sum.hours = hours + s.hours + sum.mins / 60;
	sum.mins = sum.hours % 60;
	return sum;
}
Time Time::operator-(const Time& s) const
{
	Time diff;
	int total1, total2;
	total1 = hours * 60 + mins;
	total2 = s.hours * 60 + s.mins;
	diff.mins = (total1 - total2) % 60;
	diff.hours = (total1 - total2) / 60;
	return diff;
}
Time Time::operator*(double t) const
{
	Time Result;
	int totalMins;
	totalMins = (hours * 60 + mins)*t;
	Result.mins = totalMins % 60;
	Result.hours = totalMins / 60;
	return Result;
}
Time operator*(double m, const Time &T)
{
	Time result;
	int total = (T.hours * 60 + T.mins)*m;
	result.hours = total / 60;
	result.mins = total % 60; 
	return result;
}
std::ostream & operator<<(std::ostream & os, const Time & t)
{
	os << t.hours << " hours," << t.mins << " mins";
	return os;
}


主函數:

#include"operater_overloading.h"
int main()
{
	using namespace std;
	Time aida(5, 30);
	Time soda(6, 42);
	cout << "aida: " << aida << "\n" << "soda: " << soda<<endl;
	Time temp;
	temp = aida + soda;
	cout << "aida + soda: " << temp << endl;
	temp = soda - aida;
	cout << "soda - aida: " << temp << endl;
	temp = aida*1.5;
	cout << "aida*1.5: " << temp << endl;
	cout << "10*aida: " << 10 * aida << endl;
}

運行結果:



在上面的例子中,我取一條語句進行解釋一下:Time operator+(const Time & S) const

第一個Time表示該重載運算符後返回的數據的類型是一個Time類,後面的加號表示重載的運算符是加號,該重載運算符中包含一個參數S,參數的類型爲Time引用,最後面的一個const表示運算符重載返回的值不可修改。

總之,operator+()函數的名稱使得函數表示法或運算符表示法來調用它,那如果有以下這種形式的運算,是否合法呢?

假設A,B,C,D都是Time類,那麼如下運算形式是否正確呢?

Time A,B,C,D;

.....

D=A+B+C;

爲了回答上面那個問題,我們將上面的那個語句轉換爲函數調用吧,由於c++是從左到右的結合的運算符,因此可以轉換爲下面的形式:

D=A.operator+(B+C);

然後,函數參數本身就被轉換爲一盒函數調用,結果如下:
D=A.operator+(B.operator+(C));

上述語句合法嗎?是的,函數調用B.operator+(C)並返回一個Time類,然後將這個返回的類作爲A.operator+()調用的參數,因此上述的方式是合法。

從上面的實例可以看出,使用一些運算符重載可以使得程序更加簡潔,類之間可以直接實現四則運算操作,重載爲成員函數時,總時隱含了一個參數,該參數是this指針。this指針是指向調用該成員函數對象的指針。

其實,運算符重載形式有兩種,一是重載爲類的成員函數,二是重載爲類的友元函數 上述實例中的運算符重載之後是類Time的成員函數,因此可以總結一下:

運算符重載爲類的成員函數的一般語法形式爲: 

函數類型 operator 運算符(形參表) 

  
函數體; 

運算符重載就是賦予已有的運算符多重含義。通過重新定義運算符,使它能夠用於特定類的對象執行特定的功能,這便增強了C++語言的擴充能力。

上面舉得例子是運算符重載爲類的成員函數,那麼重載爲友元函數是啥樣子呢

其實細心的同學應該可以看到乘法的運算符重載是Time operator*(double t)const;那麼要使用它的話,只能是這種形式:左側爲調用對象,右側爲調用對象的參數。

A=B*1.5;//等價於A=B.operator(1.5);

 那麼,如果如果存在這種形式:A=1.5*B ,這明顯不能使用上面的乘法運算符重載,遇到這種情況該怎麼辦呢?重載爲友元函數是時候登場了。首先介紹一下,如何創建友元。

創建友元函數的第一步是將其原型放在類的聲明中,並在原型聲明前面加上關鍵字friend,在上面的頭文件中,其實已經聲明瞭兩個友元函數:

friend Time operator*(double m, const Time& T){ return T*m; }//友元重載
friend std::ostream & operator<<(std::ostream & os, const Time &t);//友元重載

該原型意味着下面兩點:

(1)雖然operator*()函數是在類的聲明中聲明的,但它不是類的成員函數,因此一定不能使用成員運算符來調用它;

(2)雖然operator*()函數不是成員函數,但他與成員函數的訪問權限是相同的;

第二步是編寫友元函數的定義。因爲他不是成員函數,所以在定義的時候不要使用Time::限定符,另外在定義中也不要使用關鍵字friend,定義形式如下:

Time operator*(double m, const Time &T)
{
	Time result;
	int total = (T.hours * 60 + T.mins)*m;
	result.hours = total / 60;
	result.mins = total % 60; 
	return result;
}
有了上述的聲明和定義之後,語句A=1.5*B就可以調用剛纔定義的非成員的友元函數:

A=operator*(1.5,B);

從上面的形式可以看出重載爲友元函數定義格式一般是下面的這個樣子:

重載爲友元函數的運算符重載函數的定義格式如下:

 

 friend <類型說明符> operator <運算符>(<參數表>)

  {……}

上面的友元重載是:重載*運算符,其實還有比較常見的<<重載,這裏就不介紹了,上面的例子中就包含了<<友元重載。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章