第十一章:運算符重載,友元函數,重載

運算符重載

1、什麼是運算符重載

運算符重載也就是同一個運算符在不同的運算表達式中表示的含義不一樣,也就是實現的功能不一樣。
比如:2*3 = 6,*號實現的功能是將兩個整數相乘。int num; int *pnum = #此時的*號是用來定義一個指向num的指針變量。這個時候*就是實現了運算符重載。
比如:True && False,&號是將兩個變量相與。int *pnum = #此時&號是用來獲得變量num的地址。這個時候&就是實現了運算符重載。
比如:cout << "string" << endl; << 爲輸出運算符,它還表示左移運算符。
比如:cout << "string" << endl; <<運算符與cout一起實現了輸出字符串功能,同樣我們可以通過運算符重載使得<<運算符與cout來輸出我們自定義的任意對象。
比如:2 + 3 = 5;+實現了整數的加法,同時我們可以通過將+運算符重載,實現將兩個自定義的對象實現加法。

2、如何實現運算符的重載

比如:現在有一個表示時間的類

class Time
{
private:
	int hours;
	int minutes;
public:
	//下面是各種成員函數
	Time();
	~Time();
	void AddMin(int m);
	void AddHr(int h);
	void Reset();
	void show() const;
	Time Sum(const Time & t) const;
};
成員函數Sum是爲了將兩個對象求和。Time sum = time1.Sum(time2);
//sum爲對象time1和time2的和。這樣比較麻煩,同時也不直觀。如果我們可以直接使用sum = time1 + time2;就顯得非常方便。
這樣的話,我們必須要對+運算符進行重載,方法如下。將Sum()成員函數用下面的成員函數替換。
Time Time::Sum(const Time & t) const
{
	Time sum;
	sum.minutes = minutes + t.minutes;
	sum.hours = hours + t.hours;
	sum.hours += sum.minutes / 60;
	sum.minutes = sum.minutes % 60;
	return sum;
}
Time Time::operator+(const Time & t) const
{
	Time sum;
	sum.minutes = minutes + t.minutes;
	sum.hours = hours + t.hours;
	sum.hours += sum.minutes / 60;
	sum.minutes = sum.minutes % 60;
	return sum;
}

同樣的可以實現減法和乘法的運算符重載

Time operator-(const Time & t) const;
Time operator*(double n) const;

友元函數

1、什麼是友元函數

在類中只有成員函數可以訪問類的私有數據成員。但是有時候會顯得太過嚴格。所以定義了另外一個友元函數,和成員函數有相同的訪問權限。
但是它不是成員函數。

2、爲何需要友元

就比如上面的*號運算符重載,使用的時候是 time2 = time1 * 3.8;這時函數調用方法爲,time2 = time1.operator*(3.8);
但是有時候我們需要寫成time2 = 3.8 * time1;如果寫成這樣的話,*運算符重載就不能使用了。必須要有新的方法來實現這樣運算。
可以用一個帶有兩個形參的函數,Time operator*(double db, const Time & t);與time2 = operator*(3.8, time1);匹配
但是問題就來啦,這個函數的形參是對象本身,它不能調用這個函數,所以這個函數不能是類成員函數。
但是如果不是類成員函數的話,那麼它怎麼訪問類的成員,t.hours和t.minutes;?????????
這個時候就需要將該函數定義爲友元,從而該函數有權限訪問對象的私有數據成員。

3、定義友元函數

friend Time operator*(double db, const Time & t);
在類中定義,前面加上關鍵字friend,表示這個是友元函數。可以訪問對象的私有數據成員。


重載<<運算符,實現用cout << 來直接輸出對象的內容。

cout << time1;

1、是成員函數還是非成員函數

如果<<重載運算符爲類成員函數,則需要用time1來調用,time1必須爲第一個參數,就只能這樣寫了 time1 << cout;顯然這樣不對。
所以應該是非成員函數,且格式差不多爲 void operator<<(ostream & os, const Time & t);

2、函數的返回值應該是什麼?

如果,語句爲cout << time1;上面語句完全可以實現,但是cout << time1 << time2 << time3;就不能實現了。因爲輸出time1之後的返回值爲void。
所以爲了實現連續輸出,函數的返回值必須是ostream & 。
所以,函數爲ostream &operator<<(ostream & os, const Time & t);

3、是友元函數嗎

因爲不是非成員函數,還要有訪問對象私有數據成員的權限,必須是友元函數啦。
最終的函數原型爲:friend ostream & operator<<(ostream & os, const Time & t);


#pragma once
#include <iostream>
using namespace std;
class Time
{
private:
	int hours;
	int minutes;
public:
	Time(void);
	~Time(void);
	Time(int h, int m = 0);
	void AddMin(int m);
	void AddHr(int h);
	void Reset(int h = 0, int m = 0);
	Time Sum(const Time & t) const;
	Time operator+(const Time & t) const;
	Time operator-(const Time & t) const;
	Time operator*(double n) const;
	friend Time operator*(double n, const Time & t);
	void Show() const;
	friend ostream & operator<<(ostream & os, const Time & t);
};

#include "Time.h"
#include <iostream>
using namespace std;

Time::Time(void)
{
}

Time::Time(int h, int m)
{
	hours = h;
	minutes = m;
}

Time::~Time(void)
{
}
/*	void AddMin(int m);
	void AddHr(int h);
	void Reset(int h = 0, int m = 0);
	Time Sum(const Time & t) const;
	void Show(const Time & t) const;*/
void Time::AddMin(int m)
{
	int sum = 0;
	sum = minutes + m;
	hours += sum / 60;
	minutes = sum % 60;
}
void Time::AddHr(int h)
{
	hours += h;
}
void Time::Reset(int h, int m)
{
	hours = h;
	minutes = m;
}
Time Time::Sum(const Time & t) const
{
	Time sum;
	sum.minutes = minutes + t.minutes;
	sum.hours = hours + t.hours;
	sum.hours += sum.minutes / 60;
	sum.minutes = sum.minutes % 60;
	return sum;
}
Time Time::operator+(const Time & t) const
{
	Time sum;
	sum.minutes = minutes + t.minutes;
	sum.hours = hours + t.hours;
	sum.hours += sum.minutes / 60;
	sum.minutes = sum.minutes % 60;
	return sum;
}
Time Time::operator-(const Time & t) const
{
	int sum1 = 0;
	int sum2 = 0;
	Time time1;

	sum1 = hours*60 + minutes;
	sum2 = t.hours*60 + t.minutes;
	if (sum1 > sum2)
	{
		time1.minutes = (sum1 - sum2) % 60;
		time1.hours = (sum1 - sum2) / 60;
	}
	else
	{
		time1.minutes = (sum2 - sum1) % 60;
		time1.hours = (sum2 - sum1) / 60;
	}
	return time1;
}
Time Time::operator*(double n) const
{
	long minute;
	Time sum;
	minute = hours * 60 * n + minutes * n;
	sum.minutes = minute % 60;
	sum.hours = minute / 60;
	return sum;
}
Time operator*(double n, const Time & t)
{
	long minute;
	Time sum;
	minute = t.hours * 60 * n + t.minutes * n;
	sum.minutes = minute % 60;
	sum.hours = minute / 60;
	return sum;
}
/*
友元函數也可以爲下面這種方式實現
Time operator*(double n, const Time & t)
{
	return t * n;
}
*/
void Time::Show() const
{
	cout << hours << " Hours and " << minutes << " minutes.\n";
}
//因爲友元函數不是類成員函數,所以不用使用Time::
ostream & operator<<(ostream & os, const Time & t)
{
	os << t.hours << " Hours and " << t.minutes << " minutes.\n";
	return os;
}

#include <iostream>
#include "Time.h"

using namespace std;

int main()
{
	Time t1(2, 30);
	Time t2(1, 40);
	Time t3(3, 10);

	t1.Show();
	t2.Show();
	Time sum;
	//sum = t1.Sum(t2);
	sum = t1 + t2;
	sum.Show();
	sum = t3 - t1;
	sum.Show();
	sum = 2 * t1;
	sum.Show();
	cout << sum;

	getchar();
	return 0;
}

類型轉換

1、什麼是類型轉換

比如:long count = 8;//將整型數據變爲長整型數據
比如:int num = 8.9;//將雙精度數據變爲整型數據
比如:int * p = (int *) 10;//將整數10強制類型轉換爲指針類型
等等
同樣的道理,我們可以將一個對象的類類型轉換爲其它數據類型,比如double, int....
或者是將一個int,double類型的數轉換爲對象類型

2、舉個例子

#pragma once
class Stonewt
{
private:
	enum {Lbs_per_stn = 14};
	int stone;
	double pds_left;
	double pounds;
public:
	Stonewt(void);
	Stonewt(int stn, double lbs);
	Stonewt(double lbs);
	~Stonewt(void);
	void show_lbs() const;
	void show_stn() const;
};

在這個例子中,如果有下面的語句:
Stone st1;
st1 = 276.8;//這條語句將會調用構造函數Stonewt(double),將276.8轉換爲一個Stonewt值。
str1 = 89;//這條語句將會首先將89轉換爲double類型,然後調用構造函數Stonewt(double),將89.0轉換爲Stonewt值。

但是,問題就是,可以將數字轉換爲對象,能不能將對象轉換爲數字啊??也就是Stonewt st1(28.9);   double num = st1;

Stonewt st1(28.9);
double num = st1;

可以這樣做,但不是使用構造函數。構造函數只是用於從某種類型到類類型的轉換。
如果要進行相反的轉換,必須要用到C++特殊的運算符函數-------轉換函數。
如果定義了轉換函數,就可以這樣使用:

Stonewt st1(28.9);
double num = double(st1);//強制轉換
或者直接是
double num = st1;//隱式轉換


3、轉換函數定義

operator int();
operator double();


#pragma once
class Stonewt
{
private:
	enum {Lbs_per_stn = 14};
	int stone;
	double pds_left;
	double pounds;
public:
	Stonewt(void);
	Stonewt(int stn, double lbs);
	Stonewt(double lbs);
	~Stonewt(void);
	void show_lbs() const;
	void show_stn() const;

	//轉換函數
	operator int() const;
	operator double() const;
};

#include "Stonewt.h"
#include <iostream>
using namespace std;
/*
private:
	enum {Lbs_per_stn = 14};
	int stone;
	double pds_left;
	double pounds;
public:
	Stonewt(void);
	Stonewt(int stn, double lbs);
	Stonewt(double lbs);
	~Stonewt(void);
	void show_lbs() const;
	void show_stn() const;
*/

Stonewt::Stonewt(void)
{
	stone = 0;
	pds_left = pounds = 0.0;
}

Stonewt::Stonewt(double lbs)
{
	pounds = lbs;
	stone = pounds / Lbs_per_stn;
	pds_left = pounds / Lbs_per_stn;
}
Stonewt::Stonewt(int stn, double lbs)
{
	stone = stn;
	pds_left = lbs;
	pounds = stone * Lbs_per_stn + pds_left;
}

Stonewt::~Stonewt(void)
{
}

void Stonewt::show_lbs() const
{
	cout << "pounds: " << pounds << endl;
}

void Stonewt::show_stn() const
{
	cout << "stone: " << stone <<  " pds_left " << pds_left << endl;
}
//轉換函數
Stonewt::operator int() const
{
	return int(pounds + 0.5);
}
Stonewt::operator double() const
{
	return pounds;
}

#include <iostream>
#include "Stonewt.h"

using namespace std;

int main()
{
	Stonewt st1(9, 2.8);
	double pst1 = st1;
	
	cout << "st1 轉換爲double爲 " << pst1 << endl;
	int num = int(st1);
	cout << "st1 轉換爲int爲 " << num << endl;
	getchar();
	getchar();
	return 0;
}

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