第十一章:运算符重载,友元函数,重载<<运算符,类的自动转换和强制类型转换

本文深入解析C++中运算符重载和类型转换的概念、实现方法及应用实例,包括如何通过成员函数和友元函数重载运算符,以及如何实现自定义类型之间的类型转换。

运算符重载

1、什么是运算符重载

运算符重载也就是同一个运算符在不同的运算表达式中表示的含义不一样,也就是实现的功能不一样。
比如:2*3 = 6,*号实现的功能是将两个整数相乘。int num; int *pnum = &num;此时的*号是用来定义一个指向num的指针变量。这个时候*就是实现了运算符重载。
比如:True && False,&号是将两个变量相与。int *pnum = &num;此时&号是用来获得变量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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值