一.为什么要运算符重载
为了使自定义类型可以直接使用运算符,以适应不同的数据类型。
二.使用方法
1.关键字:operator,通过关键字来定义运算符重载(跟写个函数一样)
2.函数名:operator+运算符
返回类型 operator 运算符(参数列表)
{
函数体;
}
三.使用规则
C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。
C++中绝大部分的运算符允许重载,如:
双目运算符 | + - * / % |
关系运算符 | == != < <= > >= |
逻辑运算符 | && || ! |
单目运算符 | +(正号) -(负号) *(指针) &(取地址) ++ -- |
位运算 | & | ~ ^ <<(左移) >>(右移) |
赋值运算符 | = += -= *= /= %= &= |= ^= <<= >>= |
内存分配 | new delete new[ ] delete[ ] |
其他 | ( ) 函数调用 -> 成员访问 [ ] 下标 , 逗号 |
不允许重载的只有5个,如:
重载的部分规则: 运算符函数的参数至少有一个必须是类的对象或者类的对象的引用。
成员访问运算符 | . |
成员指针访问运算符 | * |
条件运算符 | ? : |
域运算符 | :: |
长度运算符 | sizeof |
成员访问运算符和成员指针访问运算符不能重载是为了保证访问成员的功能不能被改变。
条件运算符不能被重载是为了保证在判断后可以成功跳转执行。
域运算符和sizeof运算符的运算对象是类型,而不是变量或一般表达式,不具备重载的特征。
规则:
1.重载不能改变运算符运算对象(即操作数)的个数。
2.重载不能改变运算符的优先级别。
3.重载不能改变运算符的结合性。
4.重载运算符的函数不能有默认的参数。否则,就改变了运算符参数的个数。
四.重载单目运算符
单目运算符只有一个操作数,如 !a, -b, &c, *p,还有常用的 ++i 和 --i 等。
例如int++,和 ++int :
#include<iostream>
using namespace std;
class Add
{
public:
Add(int a1=0,int b1=0)
{
a = a1;
b = b1;
}
Add& operator++()
{
++a;
++b;
return *this;
}
Add operator++(int)
{
Add tmp = *this;
++(*this);
return tmp;
}
void print()
{
cout << "a=" << a << "," << "b=" << b << endl;
}
private:
int a;
int b;
};
int main()
{
Add a1(1, 2), a2(3, 4);
(a1++).print();
(++a2).print();
return 0;
}
五.重载双目运算符
双目运算符(或称 二元运算符),双目运算符有两个操作数,通常在运算符的左右两侧。
例如:Date类进行日期比较
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& dd)
{
_year = dd._year;
_month = dd._month;
_day = dd._day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
bool operator==(const Date& y)
{
return _year == y._year &&
_month == y._month &&
_day == y._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 5, 7);
Date d2(2024, 5, 5);
bool ret= d1 == d2; // d1.operator==(d2)
cout << ret;
return 0;
}
六.重载赋值运算符
1.重载格式:
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要复合连续赋值的含义注意:是两个已经存在的对象进行拷贝。
2.赋值运算符只能重载成类的成员函数不能重载成全局函数。(它里面没有this指针了,所以要给两个参数)
3.用户没有显式实现时,编译器会生成一个默认赋值运算符重载,是浅拷贝。对于需要深拷贝的就会有危险。
例如:Date类进行日期赋值
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& dd)
{
_year = dd._year;
_month = dd._month;
_day = dd._day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
//d1=d3
Date& operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 5, 7);
Date d3;
Date d2;
d2 = d3 = d1;
d3.Print();
return 0;
}