前言

重载不陌生

1
2
3
4
5
6
int add(int a){
return ++a;
}
int add(int a,int b){
return a + b;
}

函数重载就是一种。


正文

运算符重载就是利用常见的运算符+-*/去做一些重载的事情。

比如string就可以实现+=

1
2
string str = "hello ";
str += "world";

默认的+肯定是只能对数值类型进行数学运算,而string这种重新设计的+就是运算符重载

语法:返回值类型 operator运算符();

自定义一个类

1
2
3
4
5
class Box{
public:
int height;
Box(int h):height{h} {}
};

在正常情况下,比较两个实例化对象的height属性

1
2
3
4
5
6
Box b1(100);
Box b2(150);

if(b1 < b2){
... //肯定是不行的,因为类和类之间不支持用<>比大小
}

按照常规逻辑,就是写一个函数

1
2
3
bool toBig(Box &ba, Box &bb){
return ba.height < bb.height;
}

然后if在去判断这个返回值。


非成员函数运算符重载

那么如果有了运算符重载。

1
2
3
bool operator<(Box &ba, Box &bb){
return ba.height < bb.height;
}

但是,这样在形式上看着可能跟函数换汤不换药的感觉。

在实际用的时候

1
if (b1 < b2) std::cout << "b2 big" << std::endl;

本质上是if (operator<(b1, b2)) std::cout << "b2 big" << std::endl;
既然是运算符重载,自然会转换成上面那种形式,因为有了模板,他就知道放两个类的时候,用什么比较。

如果变量是私有的,普通情况不具备访问权限,就可能要用friend友元操作,但是不是特别好

既然是模板,除了类和类,也可以用其他类型

1
2
3
bool operator<(Box &ba, int x){
return ba.height < x;
}

只不过像short float double那些还要额外重载。


成员函数运算符重载

上述的非成员就是不定义在类中,定义在类中的也好写

1
2
3
4
5
6
7
8
9
class Box{
public:
int height;
Box(int h):height{h} {}

bool operator<(Box &ba){
return this->height < ba.height;
}
};

可以看到这个运算符重载是写在类中的。是属于类的成员。

与上述的本质也有差异if (b1.operator<(b2)) std::cout << "b2 big" << std::endl;

因为运算符重载通过函数模式发生,所以谁调用的就跟谁连在一起


为什么会有重载运算符

  1. 最主要就是让类也支持原生的运算
  2. 提示对程序的控制权,比如重载new delete new[] delete[]

但是注意,运算符的重载只是为了让代码更方便使用和维护,并不能提升什么开发效率


运算符重载的限制

  1. 只能通过现有运算符,不能自定义
  2. 有些运算符不能重载
    1. 对象访问.,比如user.hp
    2. 作用域解析::,std::cout
    3. 求大小运算符sizeof
    4. 三目运算?:
  3. 无法修改运算符本身优先级
  4. 在c++17之后,也不能修改运算符的操作数计算顺序,17之前 编译器可以自由选择,但是仍然是一种未定义行为
  5. 除了delete/delete[]和new/new[]外,不能对原生数据类型的其他运算符重载,比如char的+定义为-
  6. 除了new和delete以外,其他运算符的操作数的个数一律不能修改

不建议重载逻辑运算符,因为逻辑运算符重载之后将不会进行短路测试
c++17后计算的顺序规定为先计算左边在计算右边


运算符重载的正确姿势

1
2
3
4
5
6
7
8
// 二元运算符重载
全局函数 - 返回类型 operator 运算符(类型 左操作数,类型 右操作数)
类的成员函数 - 返回类型 operator 运算符(类型 右操作数)

// 一元运算符重载
全局函数 - 返回类型 operator 运算符(类型 操作数)
类的成员函数 - 返回类型 operator 运算符()


结语

运算符的重载借用关键字operator + 运算符符号,本质上还是跟函数差不多,只不过标准化之后优化了用起来比普通函数好很多。

然后重载的时候注意下合法问题,不要擅自做一些感觉牛皮的行为。