波奇学C++:赋值运算符重载和运算符重载

上文回顾:我们已经学会了构造函数,析构函数,和拷贝构造函数,接下来我们将学习赋值运算符重载。

赋值运算符重载

class Date
{
public:
	Date(int year = 1, int month = 1,int day=1)
	{
		_year = year;
		_month = month;
		_day = day;

	}
	//运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_day = d._day;
		_month = d._month;
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;

};

    如何使用运算符重载?

int main()
{
    Date d1(2023,4,10);
    Date d2(2023,4,10);
    d2=d1;//d2已经定义过了,不是拷贝构造
    return 0;
}
//d2的值和d1相同

运算符重载函数可以使已有的两个实例,进行拷贝复制,d2的值被修改后和d1相同。

运算符重载是对已有的两个实例,而拷贝构造函数是在一个实例初始化时对它进行拷贝构造

Date d2(d1)//拷贝构造,借助d1来实现初始化

拷贝构造常用于传参和返回值时,c++规定,传值传参和返回值时,内置类型是直接拷贝,自定义类型先调用拷贝构造,要避免自定义类型调用拷贝构造,1.用指针(指针是内置类型),2.用引用传参和作返回值。

赋值运算符重载

1.不改变被复制的对象,参数用cosnt T&

2.返回值是*this,被赋值对象,应为d2的生命周期不在重载函数内,可以用引用作返回值类型提高效率。

d3 = d2 = d1//先d1覆盖d2再赋值给d3,所以d2=d1的返回值应是d2,被赋值的对象

3.要检测是否给自己赋值。

运算符重载

上面提到的赋值运算符重载,以及接下来说的都属于运算符重载,区别在于赋值运算符重载是类对象的默认函数,即会自动生成,当然涉及到深拷贝时要自己写。其他运算符重载则不是默认函数。

运算符重载本质上是一种函数,它编译器以我们的希望的方式使用运算符,对自定义对象进行操作。下面是对<小于号的运算符重载,按我们的想法实现对日期对象进行比较。(先年后月再日)

下面是两种定义方式:

//在类里面声明,在其他文件中定义
bool Date::operator<(const Date& x) 
{
	if (_year < x._year)
	{
		return true;
	}
	else if (_year == x._year && _month < x._month)
	{
		return true;
	}
	else if (_year == x._year && _month == x._month && _day < x._day)
	{
		return true;
	}

	return false;
}
//在类外声明
bool operator<(Date d,const Date& x) 
{
	if (d._year < x._year)
	{
		return true;
	}
	else if (d._year == x._year && d._month < x._month)
	{
		return true;
	}
	else if (d._year == x._year &&d._month == x._month && d._day < x._day)
	{
		return true;
	}

	return false;
}
//调用
d1>d2;

运算重载注意的地方:

1.不能连接其他符号进行重载 如operator@

2.重载运算符必须要有个类对象类型,即不能对全是内置类型进行重载操作,有一个自定义类型就能满足目的。

3.作为类对象内置类型,参数会少一个,隐藏了默认this指针。

4. .* ?: :: . sizeof 这五个运算符不能重载。

5. 运算符重载函数的参数顺序,决定运算符使用时的顺序。

比较运算符<,>,==,!=的重载可以互相套用

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

结合== 运算符和上面的<运算符可以套用其他运算符。

如>运算符重载。

bool operator>(Date& d)
{
    return !(*this<d||*this == d);
}

+/- 和+=/-=运算符重载

+= 运算符原来的数据改变了,+ 原数据没变

a+=1;//a改变了
b=a+1//a没变

因此+=可以返回类的引用,而+必须拷贝构造一个对象,对像加减再返回,返回的是一个类。

Date& Date::operator+=( int day)
{
	if (day < 0)
	{
		*this -= -day;
		return *this;
	}
	_day += day;
	while (_day> GetMonthDay(_year, _month))
	{
		
		_day = _day - GetMonthDay(_year, _month);
		_month = _month + 1;
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}
Date Date::operator+(const int day)
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

+套用+=的代码,调用拷贝构造的次数更少。因为+肯定会调用两次拷贝构造,第一次是创建一个新的类时,第二次是返回类对象时,返回自定义对象,会先拷贝构造(上面引用中提到)。+套用+=代码,两个函数各调用一次只会调用两次拷贝构造,+=套用+代码时,各调用一次,会调用四次拷贝构造。-=/-同理。

前置++和后置++运算符重载

前置++,返回的是++后的结果,可以直接直接返回对象引用。后置++,返回的是处理前的对象,并且对象+1后的结果不返回。

首先可以把++转换为+=1,后置++可以拷贝构造一个对象返回新对象,并对原对象++,因为返回的对象是在函数内创建的,出了函数就会销毁,所以只能返回对象。

C++中为了区分前置++和后置++,让后置++重载函数接收一个int参数。

//前置加加
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
//后置加加
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

流插入,流提取重载

对<<,>>操作符进行重载

cout<<1<<2<<3<<endl;//流插入
cin>>d;//流提取

流插入/提取的顺序会赋值运算符不同,是从左往右的,

先cout<<1,然后返回cout再cout<<2。因此流提取的返回值是cout对象,cin同理。

下面代码中的out 就相当cout,是ostream 的类对象。

ostream& operator<<(ostream& out, Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << endl;
	
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	in >> year >> month >> day;
	if (year >= 0 && month >= 1 && month <= 12 && day > 0 && day <= d.GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "日期非法" << endl;
		assert(false);

	}
	return in;
}

注意上面这两个函数是全局函数。由此产生两个问题。

1.为什么是全局函数?

2.如何访问private中的成员变量?

为什么是全局函数?

ostream& Date::operator<<(ostream& out)
{
	out << _year << "年" << _month << "月" << _day << endl;
	
	return out;
}
//调用
d1<<cout

如果写在类里面,只能以上面的调用的方式来使用。因为在类函数中,this默认最左边的参数值,而运算符重载又是对参数顺序有要求,要符号我们常规的格式cout<<d1,就要把ostream& out放在最左边,由此只能使用全局函数。

那么如何访问私有成员变量呢?

在类中使用friend 把它定义为友元函数,实现全局函数对私有成员变量的访问。放在公有私有中都没问题。

class Date
{
friend ostream& operator<<(ostream& out, Date& d);
friend istream& operator>>(istream& in, Date& d);
......
}

const修饰this指针,允许普通对象和const修饰的对象都能调用。

//大于运算符重载
bool Date::operator>(const Date& d)const
{
	if (_year >= d._year)
	{
		if (_month >= d._month)
		{
			if (_day > d._day)
			{
				return true;
			}
		}
	}
	return false;
}

如参数里的const Date& d,是防止参数对象的变量被修改,而后面的const 是用来修饰隐式的this指针,防止this 指针指向的对象 被修改。

实际上相当于

bool operator>(const Date& d1 ,const Date& d);

那么使用const 最好使用,因为可以保证普通对象和const 修饰的对象都能使用。

bool Date::operator>(const Date& d);
.......
const Date d1;
Date d2;
d2>d1 //可以运行
d1<d2 //不能运行

在d1<d2 中,d1 对应this 隐式指针,而这里涉及权限放大,由只读变为可修改了。

如果修改为bool Date::operator>(const Date& d) const; 则都能运行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值