目录
一.赋值运算符重载
二.前置/后置++运算符重载
三.流输入/输出重载
四.取地址/const取地址重载
前言:
运算符重载与函数重载没有本质上的关系
运算符重载:让自定义类型对象可以用运算符,转换成调用重载函数
函数重载:支持函数名相同的函数存在
.* :: sizeof ?: . 以上五个运算符不可以重载,笔试题经常出现!
C++为了增强代码可读性,增加了运算符的重载,运算符重载是具有特殊函数名的函数
关键字:operator
语法:operator + 要重载的运算符
3 + 3 = 6,如果是日期 + 日期呢,加法运算符就不能直接使用了。在C语言中,我们可以写一个日期加法函数,然后再调用这个函数,将两个日期以参数的形式传递进去;在C++中,为了使代码更具有可读性,增加了一个特性就是操作符可以被重载,本质就是可以自己显式定义一下操作符函数,与内置的发生重载。
用赋值运算符重载举例:
#include
using namespace std;
class Date
{
public:
//构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
cout << "调用构造" << endl;
}
//日期类赋值运算符重载
Date& operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
cout << "调用重载" << endl;
return *this;
}
//打印日期
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(0,0,0);//这里会调用构造函数 因为这是初始化
Date d2(2022, 8, 9);
cout << "-----------------------------------------------" << endl;
d1 = d2;//这里会调用赋值运算符重载
cout << "-----------------------------------------------" << endl;
d1.Print();
return 0;
}
赋值运算符重载后,看似d1 = d2是直接使用的
本质是:如果在类内重载的话,等价于d1.operator=(d2);
如果在类外重载的话,等价于operator=(d1,d2);d1是左操作数,d2是右操作数
赋值运算符的返回值可以起到“链式编程”的作用,例如d4 = d1 + d2 + d3;
赋值运算符只能在类内重载,不能在全局重载
原因:如果我们不显式的定义赋值运算符重载,编译器会默认生成,如果我们在全局重载的话,在调用时,例如d1=d2,会引发歧义,这时编译器不知道应该调用哪一个。
编译器默认生成(类内):Date& operator(const Date& d)
全局显式定义:Date& operator(Date& d1, const Date& d2)
有人会问这两个参数不是不同吗?别忘了编译器在类内生成的成员函数是有this指针的,也就是Date& this。
但其实不让我们在全局显式定义赋值运算符的重载只是编译器的强制行为,因为d1=d2这样调用会有二义性,但是如果d1.operator=(d2)这样就会调用类内的,operator=(d1,d2)这样就会调用全局的。
总结:
1.如果不写赋值运算符重载,编译器会在类内生成一个
2.不能在全局写赋值运算符的重载(编译器强制行为),如d1 = d2,调用会发生二义性
3.编译器默认生成的赋值运算符重载对于内置类型值拷贝(浅拷贝),对于自定义类型调用其自己的赋值运算符重载
规定:前置运算符重载没有参数,后置运算符重载有一个int占位参数
在类内或全局都可以重载
(这里为了重点展示运算符重载对于日期准确性不做要求)
1.前置++运算符重载(日期类类内实现)
Date& operator++()
{
_day++;
return *this;
}
2.后置++运算符重载(日期类类外实现)
Date operator++(Date& d, int)
{
Date copy = d;
d._day++;
return d;
}
整体代码:
#include
using namespace std;
class Date
{
friend Date operator++(Date& d, int);
public:
Date(int year, int month, int day)
:_year(year), _month(month), _day(day)
{
}
//这里为了重点展示运算符重载对于日期准确性不做要求
//前置++运算符重载
Date& operator++()
{
_day++;
cout << "前置++" << endl;
return *this;
}
private:
int _year;
int _month;
int _day;
};
Date operator++(Date& d, int)
{
Date copy = d;
d._day++;
cout << "后置++" << endl;
return d;
}
int main()
{
Date d1(2022, 8, 10);
d1++;
++d1;
return 0;
}
流输入/流输出运算符一定要在全局重载
因为如果在类内重载的话,加入实例化对象d1,那么调用函数一定是d1.operator<<(cout),这里d1与cout位置就反了,应该cout在左,d1在右,例如cout< 1.流输入重载 2.流输出重载 整体代码: 当我们没写这两个运算符重载(一般不用写),系统默认生成 1.对普通变量取地址操作符的重载 2.对const变量取地址操作符的重载 可以看到我们没写针对Date类的取地址,系统也没有报错 本质: 1.对普通变量取地址操作符的重载 2.对const变量取地址操作符的重载istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator<<(ostream& out, Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
}
class Date
{
friend istream& operator>>(istream& in, Date& d);
friend ostream& operator<<(ostream& out, Date& d);
public:
private:
int _year;
int _month;
int _day;
};
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator<<(ostream& out, Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
}
int main()
{
Date d1;
cout << "输入:年 月 日" << endl;
cin >> d1;
cout << "打印:年 月 日" << endl;
cout << d1 << endl;
return 0;
}
四.取地址/const取地址重载
class Date
{
public:
Date(int year, int month, int day)
:_year(year), _month(month), _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 8, 10);
cout << &d1 << endl;
const Date d2(2022, 8, 20);
cout << &d2 << endl;
return 0;
}
Date* operator&()
{
return this;
}
const Date* operator&() const
{
return this;
}