C++中的运算符重载

314 阅读4分钟

运算符重载(operator overload)

运算符重载可以为运算符增加一些新的功能

+ 的运算符重载

场景运用:希望获取两个坐标相加后得到的新坐标

按照之前的思路应该会是如下代码:

image.png

当然对于addPoint这个函数来说就是将两个坐标的x和y分别相加后得到一个新的坐标,那么更简单已读的一定是使用+来表达,类似于p1 + p2,如果是这样就要运用到运算符重载了

很简单只要如下图这样做即可

image.png

但其实运算符重载也是一个函数,只不过名字比较特殊,p1 + p2其实等价于operator+(p1, p2),这一点在汇编代码中也可以看的明白

image.png

但是上面写的+重载的函数并不严谨,对象作为参数直接传入的话会调用拷贝构造函数产生中间对象,所以对象类型作为参数并不好,应该使用引用类型并且加上const会使参数接收范围更广,如下:

image.png

下一步的优化是将运算符重载函数放入Point类中当做成员函数

image.png

但是还有一个问题,先看下面代码,这样是将10赋值给30显然不合理

image.png

但是我们代码现在是可以这样,p1+p2产生的一个匿名对象,而且还给这个匿名对象赋值其实没什么意义,如同上述例子所讲,所以应该禁止这样做

image.png

修改让返回值是常量对象即可解决上述问题

image.png

但是如上修改会造成多个点相加会出错

image.png

这个原因就是const对象只能调用const成员函数或者static函数,所以要讲重载函数声明为const成员函数

image.png

拷贝构造函数的一点疑问

刚才的问题让人联想到拷贝构造函数的格式一直是个固定的,今天来探究下为何如此,假如是下面这样:

Point(Point p) {

}

如果不使用引用类型会造成死循环的问题,因为在使用Point p2 = p1这样的语句时就会调用拷贝构造函数,但是在当p1作为参数传入时其实是Point p = p1,这时又会调用拷贝构造函数并将p1作为参数传入,这样就会陷入死循环,所以要使用引用类型,其次加上const后既可以接收const参数也可以接收非const参数

- 运算符重载

+运算符重载一样,如下

image.png

+= 运算符重载

返回值和参数都使用引用类型就是防止产生额外的对象

image.png

== 运算符重载

声明成const函数是可以让const对象也可以使用

image.png

!= 运算符重载

同上面 == 运算符重载

image.png

单目运算符重载

- 运算符重载

就是负号的意思,将点的xy坐标都取反

image.png

返回值是const是因为int a = 10; (-a) = 20这样本身就不可以,另外函数类型是const是确保(-(-a))可以正常运算

++ 运算符重载

首先明确++运算符有前置和后置的区分

image.png

从汇编可以看出二者的区别:

  • 前置++是先执行 a = a + 1然后再将加过1a放在那里与5相加
  • 后置++是先将a中的10取出与5相加后才执行a = a + 1

image.png

所以前置++可以进行赋值操作而后置++不可以,所以重载也要遵循这个规则

image.png

前置++ 运算符重载

image.png

后置++ 运算符重载

image.png

输入输出运算符重载

<< 输出运算符重载

image.png

>> 输入运算符

image.png

与输出运算符重载不同的是Point参数不能带有const,因为输入这里本来就是要修改Point参数

调用父类的重载运算符

重载运算符的本质也是函数,直接在子类中调用父类的重载运算符即可

image.png

总结:

  • 有些运算符不可以被重载

    • 对象成员访问运算符:
    • 域运算符::
    • 三目运算符?:
    • sizeof
  • 有些运算符只能重载为成员函数

    • 赋值运算符:=
    • 下标运算符:[]
    • 函数运算符:()
    • 指针访问成员: ->