CD22.【C++ Dev】类和对象(13) 流提取运算符的重载和const成员

目录

1.流提取运算符>>的重载

知识回顾

重载方法

operator<<格式

operator>>格式

使用cin对日期类对象写入数据

如果想指定格式输入

方法1:getchar()

方法2:使用临时变量接收字符

完善operator>>代码(修bug)

2.类中的权限问题(const成员)

问题

分析

建议

解释:成员函数后面加const以后普通对象和const对象都可以调用

3.const练习


承接CD21.【C++ Dev】类和对象(12) 流插入运算符的重载文章

1.流提取运算符>>的重载

知识回顾

流提取运算符的基础知识参见CC2.【C++ Cont】初认识cout,cin和endl文章

重载方法

CD21.【C++ Dev】类和对象(12) 流插入运算符的重载文章的operator<<重载格式一样

operator<<格式

ostream& operator<<(ostream& out, const Date& d)

operator>>格式

(来自https://legacy.cplusplus.com/reference/istream/istream/operator%3E%3E/)

查资料可知,返回值应该为istream&,第一个参数的也为istream&

istream& operator>>(istream& in, const Date& d)
{
	//......
	return in;
}

 注意:两个参数都不能使用const修饰

1.cin是一个全局对象,输入实际上是通过的cin这个对象,输入的东西需要cin去接受,如果加了const,cin就无法修改

2.由于需要对d的成员变量写入数据,不能加const

在类里面写operator>>友元函数声明,便于访问私有成员变量:

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
    //......
private:
	int _year;
	int _month;
	int _day;
};

使用cin对日期类对象写入数据

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

测试代码:

#include "Date.h"
int main()
{
	Date d1(0, 0, 0);
	cin >> d1;
	cout << d1;
	return 0;
}

运行结果:

如果想指定格式输入

方法1:getchar()

例如输入2025/3/31.可以这样修改代码

istream& operator>>(istream& in, Date& d)
{
	in >> d._year;
	getchar();
	in >> d._month;
	getchar();
	in>> d._day;
	return in;
}

运行结果:

方法2:使用临时变量接收字符

该临时变量仅接收字符,并无实际作用,所以起名为unused

istream& operator>>(istream& in, Date& d)
{
	char unused;
	in >> d._year >> unused >> d._month >> unused >> d._day;
	return in;
}

运行结果:

完善operator>>代码(修bug)

代码要有鲁棒性,因此需要对非法日期做处理

1.月必须介于1~12之间

2.天数必须合法

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	if (d._month < 1 || d._month>12)
	{
		cout << "非法日期" << endl;
		exit(EXIT_FAILURE);//错误退出
	}
	if (d._day <= 0 || d._day > GetMonthDay(d._year,d._day))
	{
		cout << "非法日期" << endl;
		exit(EXIT_FAILURE);//错误退出
	}
	return in;
}

(也可以将exit(EXIT_FAILURE)改成assert(false),因为里面为false,为无条件断言

其他写法:将判断条件写入assert中:

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	assert(!(d._month < 1 || d._month>12));
	assert(!(d._day <= 0 || d._day > GetMonthDay(d._year, d._month)));
	return in;
}

这样断言的好处:能具体告诉日期的哪一个部分是非法的,例如:

1.月份是非法的

2.天数是非法的

2025年不是闰年,2月最多28天

运行结果:

发现退出代码不为0,这和头文件中EXIT_FAILURE定义的值有关

(VS2022的stdlib.h中有定义)

2.类中的权限问题(const成员)

使用const绕不开权限的放大缩小平移的问题,看下面的例子:

Date中的Print函数:

void Date::Print()
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

测试代码:

#include "Date.h"
int main()
{
	const Date d1(2025, 3, 31);
	d1.Print();
	return 0;
}

报错:

分析:

Print()中隐藏的参数是this,虽然this指针的类型为const Date*,但是 const Date*中const只表示this指针本身不能修改,并没有表示this指向对象的成员变量不能修改

 实参this表示this指向的成员变量不可以修改(const Date d1(2025, 3, 31);),但Print()接收的this表示this指向的成员变量可以修改(void Date::Print()),导致权限的放大

解决方法:在Print函数后面加上const即可,const修饰*this(注意星号),这样就为权限的平移

void Date::Print() const//const修饰*this,this的类型为const Date* const
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

(注加上的const不能写在Print()的括号里面,隐式参数this类型不能在括号里面修改,这是语法规定)

运行结果:

问题

下面是权限的平移放大还是缩小?是否正常运行?

void Date::Print() const
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

//......

#include "Date.h"
int main()
{
	Date d1(2025, 3, 31);
	d1.Print();
	return 0;
}

分析

Date d1(2025, 3, 31);表示this指向的对象可以修改,void Date::Print() const表示this指向的对象不可以修改,从可以修改到不可以修改为权限的缩小,正常运行

建议

★如果对象的成员变量不改变(注意前提),最好在成员函数的后面加上const,成员函数后面加const以后普通对象和const对象都可以调用

例如日期+天数,日期类对象不改变,则在operator+函数后加上const

提醒:非成员函数上不允许修饰符const

(operator<<不是成员函数,没有使用Date::)

但也不能不看实际情况就加const

例如operator-复用了operator-=的代码,加了const就不能对*this修改

解释:成员函数后面加const以后普通对象和const对象都可以调用

测试代码:

#include "Date.h"
int main()
{
	const Date d1(2025, 3, 31);
	Date d2(2025, 4, 1);
	d1 < d2;
	d2 < d1;
	return 0;
}

分别对加了const和没有加const的operator<测试

先分析没有加const的:

bool Date::operator< (const Date& d2)
{
	if (_year < d2._year)
		return true;
	else if (_year == d2._year && _month < d2._month)
		return true;
	else if (_year == d2._year && _month == d2._month && _day < d2._day)
		return true;
	return false;
}

读测试代码可知:

d1<d2的执行会有问题,由d1的定义可知:d1的成员对象不能修改,而bool Date::operator< (const Date& d2)第一个参数为this,与d1的地址对应,导致权限的放大,会报错

d2<d1执行没有问题,是权限的缩小,没有问题

再分析加了const的:

d1<d2:权限的平移,没有问题

d2<d1:权限的缩小,没有问题

3.const练习

1. const对象可以调用非const成员函数吗?
2. 非const对象可以调用const成员函数吗?
3. const成员函数内可以调用其它的非const成员函数吗?
4. 非const成员函数内可以调用其它的const成员函数吗?

答案见下篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值