前言

递增递减就是通过++、--两个运算符。
不过它有特殊的地方就是可以放前面也可以放后面。
区别就是先递增后传值,和先传值后递增。


正文

前置++/–

1
2
3
4
5
6
7
//方法
返回类型 operator++();
返回类型 operator--();

//全局函数
返回类型 operator++(操作数类型 操作数);
返回类型 operator--(操作数类型 操作数);

这就拿之前的hint类做试验了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
class hint{
private:
char *mem[4];
public:
hint(int _val = 0);

operator int();
void operator=(int _val);
hint &operator++();


~hint();
};

hint &operator--(hint &_val);

一个做成员一个做全局。

1
2
3
4
5
6
7
8
9
hint &hint::operator++(){
*this = *this + 1;
return *this;
}

hint &operator--(hint &_val){
_val = _val - 1;
return _val;
}

前置递增因为是成员函数的关系,它递增后不需要在重新返回一个值,修改原有的就行了,这也是传递引用的原因
a = ++c + b, c自增就好,不需要额外返回,然后在加上b

效果正常,表达式中也能正常运行。


后置++/–

1
2
3
4
5
6
7
//方法
返回类型 operator++(int);
返回类型 operator--(int);

//全局函数
返回类型 operator++(操作数类型 操作数,int);
返回类型 operator--(操作数类型 操作数,int);

因为符号重载本身差不多,所以标准委员会就来了一手函数重载,用以区分前置和后置。

1
2
3
4
hint hint::operator++(int){
*this = *this + 1;
return *this;
}

直接套是不对的,后置的递增,它是先传值在递增,直接套用前置的做法不可取。

但是如果要有一个变量接受*this的值,然后*this自增,传回那个变量。
理论上可以,但是消耗内存。

1
2
3
4
5
hint hint::operator++(int){
hint _val = *this;
*this = *this + 1;
return _val;
}

而且不出意外的报错了。

因为这个临时构建的变量,它传的是一个hint类型的参数,而我们的构造函数写的是int,那么他就会调用默认的副本构造也就是拷贝函数,拷贝函数的规则不像我们传递int的写法。
而它最会执行析构函数的。。析构函数我们就是让他释放了内存,所以会出现问题。

虽然说尝试用强转的办法hint _val = (int)*this;
但是最后都要面临一个问题。
我主函数main里面定义的时候hint ht{200};
ht = ht++ ht = ht ,他又会发生一次副本构造,这就引发问题。

解决办法有一个不太稳定的,就是删除掉这种默认副本构造函数

1
hint(hint &_val) = delete;
1
2
3
4
5
hint hint::operator++(int){
hint _val = (int) * this;
*this = *this + 1;
return _val;
}

虽然编译器通过了,但这种做法不见得所有编译器都能通过。

因为我们强制转换,让*this 变成int的临时变量,然后传递给已经构造好的ht,ht本身也是用int构造的。
但是如果去掉了强制转换,也还是会报错,具体原因也不好说,毕竟副本构造都删了,充其量是个用户未定义行为了。

所以说删除有点麻烦,不如直接重构

1
2
3
hint::hint(hint &_val) :hint((int)_val){

}
1
2
3
4
5
hint hint::operator++(int){
hint _val = *this;
*this = *this + 1;
return _val;
}

这样一来也省得强制转换。

也符合预期效果。

减法就省事了

1
2
3
4
5
hint operator--(hint &_val, int){
hint val = _val;
--_val;
return val;
}

副本构造函数已经重构了,而且前置–也写过了,省去不少麻烦。


有个蛋疼的,

1
2
3
int a = 125;
++++a;
std::cout << a << std::endl;

它存在这么一种可以用很多对++复合运算。
之所以行得通,也是因为它运算的时候(++(++a)),a反正还是左值。

a++++就行不通了。因为他是a=a+1, a=a+1,a+1本身是一个右值,语义不通。

但是我们自己写的类就有这个缺陷,它可以后置++重叠。后置重叠的太多了肯定不利于阅读和理解值。
a+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

因为我们的hint++,他是(b++).++返回值是hint,有调用了一次++函数。

解决这个也很简单,给返回值修饰为const
const hint operator++(int);

修饰完了这个,记得修改一下operator int() const;
否则cout << 左移运算符的时候,因为是const hint他不知道转成什么。


结语

优化空间就是其他类型的重载,和const情况下的问题。