用C++编程的都知道,C++提供了一个非常强大的操作符重载机制,利用操作符重载,我们可以为我们自定义的类增加更多非常有用的功能。不过,C++也有限制,就是当我们为自定义的类重载操作符时,重载操作符的含义应该跟内置类型一样,比如,你不能通过重载+号操作符来实现两个数相乘的运算,实现需要是两个数相加的运算。本篇,我重点介绍下重载前置++和后置++的区别(前置--跟后置--类似)。
我们知道,写for循环年的时候,可以用下面这两种方式:
for(int i=; i<; i++) {
//do something
} for(int j=; j<; ++j) {
//do something
}
如上两种方式,i++跟++j到底有什么区别呢?
首先,这两种方式都会使得i跟j自增1, 不同的地方在于其内部实现; i++的实现原理是现将i自增1,然后返回i的引用(我们知道重载操作符也是可以有返回值的);而++j的实现原理是:先定义一个j的副本,然后在将j自增1,最后返回之前定义个那个副本的值。
通常,c++的内置类型都要求前缀式操作符返回被增量或被减量对象的引用;而要求后缀式操作符返回被增量活被减量对象做增或减操作之前的副本(这里边就存在内存拷贝)。
实际的调用过程看起来应该是这样:
for( int i=; i<; i.operator++() ) { //调用后置++
//do something
} for( int i=; i<; i.operator++() ) { //调用前置++
//do something
}
看到这里,你可能 有个疑问,为什么调用后置++的之后,参数列表要传一个0而前置++却没有传呢?
这里就牵扯出前置++跟后置++的另一个差别。
前置++和后置++在定义的都是一样,看起来应该是下边这样:
class A {
private:
int a;
public: A& operator++() {
//...
} A operator++() {
//...
} }
这样,我们就无法区分到底哪个是哪个了,也许你会说它们的返回值不是不一样吗? 我们老早就知道,无法通过不同的返回值来重载不同的函数版本。
这种情况下,为了做区分也是为了解决这一问题,一般要求后缀式操作符接受一个额外的int型形参(不会使用它,仅做区分用),来区别两者的不同。
class A {
private:
int a;
public: A& operator++() { //前置++
//...
} A operator++(int) { //后置++
//...
} }
这样,编译器将为我们提供0作为这个后缀式版本的形参。(也可以调用这个有参数的版本做前缀式操作,不过一般不应该这么做),下边是完整定义:
class A {
private:
int a;
public: A& operator++() { //前置++
++a;
return *this;
} A operator++(int) { //后置++
A a = *this;
++*this;
returnn a;
} }
如上,操作符的后缀式比前缀式复杂一些,在实现后缀式版本时,一般先保存对象做自增/减之前的副本,然后调用自己的前缀版本来实现自增操作,最后将先前年保留的副本
返回。这里需要注意的是,后缀式版本中,返回值是尚未自增的原值,但对象本身已经做了自增操作了。
( ps : --操作符的前缀式和后缀式类型)