2013年08月10日

C++ 自增操作符


More Effective C++中讲述increment/decrement操作符的内容总结

读Scott Meyers的Effective C++和More Effective C++总会找到一种浩然开朗的感觉,真真正正的刺激你更深的去拨开更多C++语言特性的面纱,昨天读了More Effective C++的条款6,讲述increment和decrement操作符的前置和后置的形式,兴奋不已,十分受用,好的文章就应该他这样写,通俗易懂,并且由浅入深!

重载

C++允许重载++和–操作符的两种形式,前置和后置的,然而前置和后置的函数名都一样,所以,使用了参数来区分前置还是后置。++和–的前置重载函数都没有参数,后置则添加了一个int形参,并且在它被调用时,编译器默默的为该int指定一个0值,重载代码如下:

class UPInt{
    public:
        UPInt& operator++();// 前置++i
        const UPInt operator++(int);// 后置i++

        UPInt& operator--();// 前置--i
        const UPInt operator--(int);// 后置i--

        UPInt& operator+=(int); // +=操作符,结合UPInts 和 ints
        
        ...
};

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

const UPInt UPInt::operator++(int){
    UPInt oldvalue = *this;
    ++(*this);
    return oldvalue;
}

有意思的地方就在于前置的重载函数和后置的重载函数返回值不一样,前置是UPInt&,而后置则是const UPInt,前置的很好理解,而后置的为什么是返回const对象了?一个函数返回const对象有什么意义?Scott Meyers给我们给出了完整的答案,对于第一个答案,有两点理由。

1.它和内建类型的行为不一致!

设计classes的一条规则是:一旦有疑虑,试看ints行为如何并遵循之。实际上,int不允许连续两次使用后置式操作符,我们不能这样:

int i;
i++++; // 错误!!!!

上面的两次后置自增是错误的,前置的++++i是可以的,是否可以理解了为什么前置的返回时UPInt&了吧!

2.即使能够两次施行后置式increntment操作符,其行为也并非你所预期!

因为第二个operator++所改变的对象是第一个operator++返回的对象,而不是原对象!即使i++++是合法的,i也只被累加一次了,这是违反直觉的。所以添加了const修饰符来禁止它合法化!第一次返回了一个const对象,然后再在该const对象上调用operator++(int)方法是不行的,const对象不能调用一个非const类型的成员函数!

其次,还需要明白的是,后置操作符中需要构造一次对象,然后析构该对象,返回该对象的副本,这样是有代价的,显然没有前置的简单明了省事!所以作者建议,对于用户定制类型时,应尽可能选择前置式的++或–操作符。

通过上面的分析,还可以明白一个问题,返回const对象到底有什么用?一般情况下,函数返回值就赋值给另一个对象了,就会调用copy construct来拷贝一份,返回的const对象貌似没什么意义了,这而就看出来了,对于直接在返回值上的操作,就很有用处了,直接阻止了用户直接在返回值上进行可能修改其值的操作,例如上面的i++++;另外还有一种情况,重载[]符号,譬如A[i],访问A[i]后,很可能有这样的操作,A[i] = x,然后到底要不要允许用户修改返回值,那就可以根据需要选择是否需要加上const!

总结

感觉一个小小的自增操作符重载还有不少知识,More Effective C++中还提到了不要随意重载&&,   和逗号操作符,大家可以去看看!关于自增操作的重载,要注意两点。

1.前置无参数,后置个int参数,仅仅用来区分二者 2.前置返回的引用,后置返回的是const 对象

前一篇: Nova Scheduler分析 后一篇: Nova Service启动