Item 6:区别Increment和Decrement操作符的前置(prefix)和后置(postfix)形式
前置和后置的区别主要在于函数参数不一样,后置形式中多了一个int型的参数,在后置形式被调用时,编译器会自动给该int型参数传0值。其次在于前置和后置形式所返回的类型不同,前置返回一个引用,后置返回一个const对象。
下面主要讲解increment的前置和后置形式,decrement类似。
//前置式:累加后取出(increment and fetch)
UPInt& UPInt::operator++() // 1
{
(*this)+=1;
return *this;
}
const UPInt UPInt::operator++(int) // 2-3
{
UPInt oldValue=*this;
++(*this); // 4
renturn oldValue;
}
首先,请看上面4处标红的地方,这些都是我们需要特别注意的地方。
1、前置返回的是引用 (&) 类型;
2、后置返回的是 const 对象;之所以是const类型,是根据内置类型(int等)的++、--的规则来要求的。对于内置类型 i++++ 是不允许的(但是 ++++i 是允许的),所以我们为自定义类型重载的 ++、-- 也应该符合这个规则。如果我们不定义返回值类型为const,那么 i++++就可以转化为 i.operator++(0) .operator(0); 得以合法执行,这是错误的。原因主要有两点:a)不符合内置类型的规则;b)计算结果错误,因为第二个后置式操作没有改变真正的对象的值,而是改变的返回对象的值。因此最好的办法就是禁止非const返回类型合法化。
3、后置有一个int型的参数,但是在函数体内并没有动用其参数,是的,以为该int型参数的唯一目的只是为了区别前置式和后置式。但是,如果你在函数体内没有使用函数的命名参数,许多编译器都会给出警告,因此为了避免这类警告,一种常见的策略是:故意略去你不打算使用的参数的名称,以上代码就是实行的这个策略。
4、这个是为了保证后置式和前置式的行为一致,才这样做的。这个保证原则是:后置式increment和decrement操纵符的实现应以其前置式的兄弟为基础。如此一来,你只要维护前置式,因为后置式会自动调整为一致的行为。
从效率方面来看:推荐大家尽量使用前置式(prefix),而不是后置式(postfix)。
因为后置式有临时对象的构造和析构,尤其对于自定义类型,造成的影响更大。