More Effective C++:自增与自减操作符的重载

    在C++中,自增与自减均有前缀形式与后缀形式。

int i = 0;
++i;       // 自增前缀形式
i++;       // 自增后缀形式
--i;       // 自减前缀形式
i--;       // 自减后缀形式

    总所周知,前缀与后缀的区别就是前缀是直接操作后再返回,而后缀则是先用临时对象保存旧值,增加旧值后再返回之前的临时对象。即有:

i = 0;
a = ++i;   // ===> i=i+1; a=i;
a = i++;   // ===> b=i; i=i+1; a=b;

    可见从实现上来讲,前缀形式比后缀形式效率要高,特别是对于自定义类型,因为少了一次临时对象的创建与释放。自增与自减的重载定义只是符号不同,而前缀形式与后缀形式则是参数不同。

#include <iostream>

using namespace std;

class MInt {
public:
	MInt& operator++();            // 后缀++
	const MInt operator++(int);    // 前缀++
	MInt& operator--();            // 后缀--
	const MInt operator--(int);    // 前缀--
	MInt& operator+=(int);
	MInt() {
		_value = 0;
	}
	~MInt() {
		cout << "in Mint dtor" << endl;
	}
	MInt& operator=(const MInt &mInt);
	int getValue() { return _value; }
private:
	int _value;
};

MInt& MInt::operator++() {
	*this += 1;
	return *this;
}

const MInt MInt::operator++(int) {
	MInt oldValue = *this;
	++(*this);       
	return oldValue;       
}

MInt& MInt::operator--() {
	*this += -1;
	return *this;
}

const MInt MInt::operator--(int) {
	MInt oldValue = *this;
	--(*this);
	return oldValue;
}

MInt& MInt::operator+=(int value) {
	_value += value;
	return *this;
}

MInt& MInt::operator=(const MInt &mInt) {
	_value = mInt._value;
	return *this;
}

int main() {
	MInt i;
	cout << "before postfix ++" << endl;
	i++;
	cout << i.getValue() << endl;
	cout << "before prefix ++" << endl;
	++i;
	cout << i.getValue() << endl;
	cout << "after all test" << endl;
	return 0;
}

     上面是完整的重载例子,由于自增与自减是差不多的,所以只测试了自增的前缀形式与后缀形式,输出如下:

before postfix ++
in Mint dtor
1
before prefix ++
2
after all test
in Mint dtor

    从上面的输出可以看到,后缀形式比前缀形式多了一个析构函数的输出,也说明了在后缀形式中,产生了临时对象。对于自定义类型来说,频繁的调用后缀形式可能会带来很大的开销,所以一般是使用前缀形式。

重载的实现

    让我们再来看看上面重载的实现,对于前缀形式与后缀形式主要的区别就是返回值类型以及参数类型。

    这里后缀形式又一个int类型参数是C++规定的,编译器可以通过该参数来区分是前缀还是后缀。当后缀形式的函数被调用的时候,编译器会传递一个0作为int参数的值给该函数,而在该函数中,并没有用到这个值。不嫌麻烦的话,也可以通过“i.operator++(0)”和“i.operator++()”来分别调用 i 的后缀形式和前缀形式的自增。

     对于后缀形式,返回值的类型是const变量,而前缀形式则是引用。对于前缀形式,这是很显然的因为要返回自增后的自己,那为什么后缀形式要返回const变量呢?如果不是const变量,则下面的代码是可以通过编译的:

MInt i;
i++++;

    就是第一个调用的++函数的返回值调用了第二个++函数,但是我们知道后缀形式返回的并不是自身,而是一个临时变量,所以第二个++函数是在一个临时变量上操作的,很显然这个语句实际上 i 只自增了一次,与我们所期望的是不一样的。还有就是内置类型是禁止连续两次后缀操作的,当我们自定义自己的类型时,一个好的准则就是使该类的行为与int类型一致。

    通过上面的重载代码,我们可以看到在后缀形式的实现中调用了前缀形式的实现,这样子我们就只需要维护前后最形式的实现就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值