【C++】类和对象——操作符operator重载 &友元函数

operator重载 —— 操作符篇

基本概念

  1. 操作符包括了">", “<”, “>=”, “<=”, "== “,”!="等
  2. 对于内置类型变量可以直接运用操作符,编译器会做处理
  3. 对于自定义类型,如:日期类,若要使用操作符,往往需要operator函数对操作符重载

operator介绍

基本用法

operator是一个函数,使用方法是operator + 需要重载的操作符,例如:operator<,这就是一个重载<操作符的重载函数名。

不能被重载的运算符

  1. 成员选择运算符:.->
  2. 作用域解析运算符:::
  3. 三元条件运算符:?:
  4. 大小运算符:sizeof
  5. 类型转换运算符:typeid
  6. 范围解析运算符:.*->*

代码示例

日期类>的操作符重载

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;	
	}

	bool operator>(const Date& d)    // > 的操作符重载
	{
		if (_year > d._year)
		{
			return true;
		}
		else if (_year == d._year)
		{
			if (_month > d._month)
			{
				return true;
			}
			else if (_month == d._month)
			{
				return _day > d._day;
			}
		}
		return false;
	}

private:
int _year;
int _month;
int _day;
};

int main()
{
	Date a(2024, 5, 28);
	Date b(2024, 5, 29);
	cout << (a > b) << endl;
	return 0;
}

==操作符重载示例

bool operator==(const Date& d)
{
	return _year == d._year 
		   && _month == d._month 
		   && _day == d._day;
}

其他操作符重载示例

[!success] 拓展思路
判断小于,可以用大于等于取反
判断小于等于,可以用大于取反
判断不等于,可以用等于取反

// 小于的操作符重载
operator<(const Date& d)
{
	return !(*this > d || *this == d);
}

// 小于等于 此处因格式问题,"< ="中间不加空格 
operator< =(const Date& d)
{
	return !(*this > d);
}

// 大于等于
operator> =(const Date& d)
{
	return (*this > d) && (*this == d);
}

输入/输出流函数重载

运用场景

需要用cout << "自定义类型变量" << endl; 的形式输入输出自定义类型。

输入流原理讲解

  1. 常规思路
    使用上面的操作符重载模板来套用。
代码示例
class Date
{
	Date(int year, int month, int day)
	: _year = year
	, _month = month
	, _day = day
	{}

	ostream& operator<<(ostream& out)
	{
		out << _year  << "年" << _month << "月" << _day << "日" << endl;
		return out;
	}
};

int main()
{
	d1(2024, 5, 29);

	cout << d1 << endl;    // 此时编译器会报错,不能通过编译
	
	d1 <<cout << endl;

	return 0;
}

此时,只能通过d1 << cout << endl;的形式打印

出现的问题

重载操作符的调用有两种,一种是直接调用函数,例如:d1.operator>(d2);
也可以直接使用操作符,例如:d1 > d2
二者在底层实现上都无区别,但是后者可读性更高,更优雅;

但是需要着重注意的是,第二种调用方式变量的先后位置要与函数声明的先后位置相对应。
也就是说,有下面的函数声明:operator<<(ostream& out);
第一个参数是编译器传入的this指针,this指针被规定必须放第一个参数位,第二个才是变量out
因此,第二种形式的调用只能写成d1 << cout << endl;此处,d1是第一个参数,中间是被重载的运算符,后边的是第二个参数

解决办法

由于this指针只传入类里面的函数。因此,只要把函数声明在类的外面,就可以自定义参数的顺序。


class Date()
{
	// ...
};

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

	return out;
}

int main()
{
	Date d1(2024, 5, 29);

	cout << d1 << endl;       // 此时会报错,报错的原因是不能够访问类的内部成员

	return 0;
}

此时编译器报错,该函数不在类的内部,不能访问类的成员

解决报错

此时使用友元函数就可以访问到类的内部成员函数

友元函数
基本概念
  1. 友元函数相当于一个声明,声明该函数可以直接访问类的内部成员。
  2. 友元函数不可被const修饰
class Date
{
	// 友元函数声明
	friend Date& Date(Date* d1, Date* d2);
};

Date& Date(Date* d1, Date* d2)
{
	// ...
}

正确的代码示例
class Date
{
	// 友元函数声明
	friend std::ostream& operator<<(ostream& out, const Date& d);	
};

ostream& std::operator<<(ostream& out, const Date& d)
{
	// ...
	return out;
}

输出流原理讲解

输出流重载的代码和输入流重载的思路差不多,这里直接代码示例

class Date
{
	friend std::istream& operator>>(istream& in, Date& d);
}

std::istream& operator>>(const istream& in, Date& d)
{
	cin >> d._year >> d._month >> d._day;
}

注意事项

  1. 输入/输出流的参数一定要加 引用&
    请添加图片描述

  2. 需要返回值以便连续调用,返回值类型是重载的操作符类型,以便链式调用,链式调用是用后一个的返回值再次调用前面的。
    cout << d1 << d2 << endl;请添加图片描述

  3. 输入/输出运算符的参数都不能用const来修饰,因为要向流函数增加新的功能
    请添加图片描述

  4. 输入流的自定义类型不能用const修饰,因为要赋值

cout/cin链式调用详解

  • cout和cin的流函数分别是ostreamistream

代码实现

int main()
{
	std::cout << "Hello" << "World" << std::endl;

	return 0;
}

具体实现过程

  1. std::cout << "Hello"调用operator<<,用于输出Hello
  2. 调用结束返回ostream&类型的std::cout的引用
  3. 此时,"Hello"位置的返回值为std::cout
  4. 因此,现在的情况可以看作是std::cout << std:: cout << "World" << std::endl;
  5. 此处的第二个std::cout便是之前World的返回值
  6. 这个返回值又调用operator<<,实现后边内容的输出
  7. 以此往复,达到链式调用的效果

重点提要

ostreamistream类型的参数或返回值必须传引用

原因:ostreamistream类型的参数不支持拷贝,且需要修改流的输入和输出,所以必须传引用


  • 30
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值