重载递增递减运算符
前言
递增递减就是通过++、--
两个运算符。
不过它有特殊的地方就是可以放前面也可以放后面。
区别就是先递增后传值,和先传值后递增。
正文
前置++/–
1 | //方法 |
这就拿之前的hint类做试验了。
1 |
|
一个做成员一个做全局。
1 | hint &hint::operator++(){ |
前置递增因为是成员函数的关系,它递增后不需要在重新返回一个值,修改原有的就行了,这也是传递引用的原因a = ++c + b
, c自增就好,不需要额外返回,然后在加上b
效果正常,表达式中也能正常运行。
后置++/–
1 | //方法 |
因为符号重载本身差不多,所以标准委员会就来了一手函数重载,用以区分前置和后置。
1 | hint hint::operator++(int){ |
直接套是不对的,后置的递增,它是先传值在递增,直接套用前置的做法不可取。
但是如果要有一个变量接受*this的值,然后*this自增,传回那个变量。
理论上可以,但是消耗内存。
1 | hint hint::operator++(int){ |
而且不出意外的报错了。
因为这个临时构建的变量,它传的是一个hint类型的参数,而我们的构造函数写的是int,那么他就会调用默认的副本构造也就是拷贝函数,拷贝函数的规则不像我们传递int的写法。
而它最会执行析构函数的。。析构函数我们就是让他释放了内存,所以会出现问题。
虽然说尝试用强转的办法hint _val = (int)*this;
但是最后都要面临一个问题。
我主函数main里面定义的时候hint ht{200};
ht = ht++
ht = ht ,他又会发生一次副本构造,这就引发问题。
解决办法有一个不太稳定的,就是删除掉这种默认副本构造函数
1 | hint(hint &_val) = delete; |
1 | hint hint::operator++(int){ |
虽然编译器通过了,但这种做法不见得所有编译器都能通过。
因为我们强制转换,让*this 变成int的临时变量,然后传递给已经构造好的ht,ht本身也是用int构造的。
但是如果去掉了强制转换,也还是会报错,具体原因也不好说,毕竟副本构造都删了,充其量是个用户未定义行为了。
所以说删除有点麻烦,不如直接重构
1 | hint::hint(hint &_val) :hint((int)_val){ |
1 | hint hint::operator++(int){ |
这样一来也省得强制转换。
也符合预期效果。
减法就省事了
1 | hint operator--(hint &_val, int){ |
副本构造函数已经重构了,而且前置–也写过了,省去不少麻烦。
有个蛋疼的,
1 | int a = 125; |
它存在这么一种可以用很多对++复合运算。
之所以行得通,也是因为它运算的时候(++(++a))
,a反正还是左值。
而a++++
就行不通了。因为他是a=a+1, a=a+1
,a+1本身是一个右值,语义不通。
但是我们自己写的类就有这个缺陷,它可以后置++重叠。后置重叠的太多了肯定不利于阅读和理解值。a+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
因为我们的hint++,他是(b++).++返回值是hint,有调用了一次++函数。
解决这个也很简单,给返回值修饰为constconst hint operator++(int);
修饰完了这个,记得修改一下operator int() const;
否则cout << 左移运算符的时候,因为是const hint他不知道转成什么。
结语
优化空间就是其他类型的重载,和const情况下的问题。