写在前面:
上一篇文章我们学了拷贝构造,还探索了操作符重载的使用,
如果有兴趣可以去看看:http://t.csdn.cn/dkD1g
今天我们接着学习类和对象相关的知识。
目录
写在前面:
1. 运算符重载
2. 赋值运算符重载
写在最后:
1. 运算符重载
来看这段代码:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
//private:
int _year;
int _month;
int _day;
};
bool operator<(const Date& x, const Date& y) {
if (x._year < y._year) return true;
else if (x._year == y._year && x._month < y._month) return true;
else if (x._year == y._year && x._month == y._month && x._day < y._day) return true;
else false;
}
int main()
{
Date d1(2023, 1, 1);
Date d2(2023, 2, 2);
cout << (d1 < d2) << endl;
return 0;
}
如果我们想让这个日期类比较大小,
我们可以专门写一个比较大小的函数来完成,
但是学习了操作符重载之后,我们就能直接使用操作符重载来完成比较了,
但是,如果把操作符重载放在类外面,那我们必须把类的成员变量放到public,
这样就破坏了类的封装性了,那如果我们直接把这个函数放进类内呢?
来看代码:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
bool operator<(const Date& x, const Date& y) {
if (x._year < y._year) return true;
else if (x._year == y._year && x._month < y._month) return true;
else if (x._year == y._year && x._month == y._month && x._day < y._day) return true;
else false;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 1, 1);
Date d2(2023, 2, 2);
cout << (d1 < d2) << endl;
return 0;
}
编译器就出现了一个报错:
说这个运算符函数的参数太多了,
这是为什么?
因为类内的成员函数有隐藏的this指针,
所以我们就留一个参数用来比较,另一个参数就是this指针,
来看代码:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
bool 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;
else false;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 1, 1);
Date d2(2023, 2, 2);
cout << (d1 < d2) << endl;
cout << d1.operator<(d2) << endl;
return 0;
}
实际上 d1 < d2 这个表达式,他本质上就是一个函数调用,
也就是 d1.operator<(d2) 。
要注意:
操作符重载只能重载C++存在的操作符,不能自创;
重载操作符必须有一个类类型参数;
用于内置类型的运算符,不能改变其含义;
作为类类型重载的时候,形参看起来比操作数少1个,实际上第一个参数是隐藏的this指针;
注意!( .* :: sizeof ?: . )这5个运算符是不能重载的!!!
2. 赋值运算符重载
来看这段代码:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 1, 1);
Date d2;
//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
d1 = d2;
return 0;
}
这个时候就需要用到赋值运算符重载,
不过这里要注意的是,拷贝构造跟赋值运算符重载是不一样的,
拷贝构造是用一个已经存在的对象初始化另一个对象,
而赋值运算符重载是两个已经存在的对象之间的复制拷贝。
那该怎么实现呢?
来看代码:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
void operator=(const Date& x) {
_year = x._year;
_month = x._month;
_day = x._day;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 1, 1);
Date d2;
//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
d1 = d2;
return 0;
}
这样真的就行了吗?
运行编译器也没有报错,好像成功了,但是,
如果你创建了三个对象的时候,你发现:
他不能支持连续赋值,
不支持:d1 = d2 = d3 这种操作,
要想让他支持连续赋值,我们需要给这个赋值运算符重载函数添加返回值:
来看代码:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
// d1 = d2
Date& operator=(const Date& x) {
_year = x._year;
_month = x._month;
_day = x._day;
return *this;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 1, 1);
Date d2;
//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
d1 = d2;
return 0;
}
这样子我们就能让赋值成功的d1的值返回了,
并且,我们的d1对象在出了函数作用域之后还在吗,还在,
所以我们使用引用返回来提高效率,减少拷贝。
实际上还有一种可能的情况,
如果有人做这样的操作呢:d1 = d1 自己调用自己呢?
所以我们最好给这段代码也加上一点判断:
#include <iostream>
using namespace std;
class Date {
public:
Date(int year = 2023, int month = 6, int day = 30) {
_year = year;
_month = month;
_day = day;
}
// d1 = d2
Date operator=(const Date& x) {
if (this == &x) { //如果是自己给自己赋值,就直接返回了
_year = x._year;
_month = x._month;
_day = x._day;
}
return *this;
}
void Print() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 1, 1);
Date d2;
//如果我们使用一个对象赋值一个对象,就会调用赋值运算符重载
d1 = d2;
d1 = d1;
return 0;
}
如果我们没有实现赋值重载函数,
编译器会默认生成一个,而这个默认生成的跟拷贝构造的规则是一样的:
对于内置类型的成员,会做值拷贝或者说浅拷贝;
而对于自定义类型成员,会调用他的赋值赋值重载。
所以,如果是像栈这样需要深拷贝的对象,我们也需要自己实现赋值重载。
这里要注意一下:
赋值重载不能重载到全局,因为他是默认成员函数,
如果我们没有实现,编译器会自动帮我们实现的,如果我们写到全局,
就会跟默认生成的发生冲突。
写在最后:
以上就是本篇文章的内容了,感谢你的阅读。
如果感到有所收获的话可以给博主点一个赞哦。
如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~