C++中的i++和++i

前置操作符和后置操作符

首先来思考一个问题:

    //下面的代码有没有区别?为什么?
    
    i++;  // i的值作为返回值,i 自增 1
    
    ++i;  // i自增 1, i 的值作为返回值

如果从原生语义上讲,不一样,但是是在单条语句内,运算结果都一样。并且如果在单条语句内,编译器会进行优化,有的是作为原生语义来进行编译,有的是直接作为同一意思来进行的。

  • 所以:
    • 现代编译器产品会对代码进行优化
    • 优化使得最终的二进制程序更加高效
    • 优化后的二进制程序丢失了C/C++的原生语义
    • 不可能从编译后的二进制程序还原C/C++程序

重载操作符


那这里再深入一下,讨论另外一个问题:

++ 操作符可以重载吗?
如何区分前置++ 和 后置++?

答案是可以重载的,不光是基本类型可以重载,类类型也可以重载。

  • ++操作符可以被重载
    • 全局函数和成员函数均可以进行重载
    • 重载前置 ++ 操作符不需要额外的参数
    • 重载后置 ++ 操作符需要一个 int 类型的占位参数

例如:

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int mValue;
public:
    Test(int i)
    {
        mValue = i;
    }
    
    int value()
    {
        return mValue;
    }
    
    // 重载前置 ++ 操作符,不需要参数
    Test& operator ++ ()
    {
        ++mValue;
        
        return *this;
    }
    
    //重载后置 ++操作符,需要一个int类型的参数
    Test operator ++ (int)
    {
        Test ret(mValue);
        
        mValue++;
        
        return ret;
    }
};

int main()
{
    Test t(0);
    
    //这里通过重载操作符,直接可以实现类类型的自加
    t++;
    
    ++t;
    
    return 0;
}

看完代码,其实也可以再次回答刚开始的问题了:

  • 区别:
    • 对于基础类型的变量
      • 前置 ++ 的效率与后置 ++ 的效率基本相同
      • 根据项目组编码规范进行选择
    • 对于类类型的对象
      • 后置 ++的重载函数中需要 新创建一个临时对象,随即又要销毁
      • 前置 ++的重载函数中不需要创建对象
      • 所以 前置 ++ 的效率高于后置 ++
      • 尽量使用前置 ++ 操作符提高程序效率

注意


看完 ++ 操作符的重载以后,其实也可以推出 -- 操作符和 ++ 操作符的重载规则是一样的,所有适用于 ++ 操作符的规则和特性也同样适用于 -- 操作符。

小结


  • 编译优化使得最终的可执行程序更加高效
  • 前置 ++ 操作符和后置 ++ 操作符都可以被重载
  • ++ 操作符的重载必须符合其原生语义
  • 对于基础类型,前置 ++ 与后置 ++ 的效率几乎相同
  • 对于类类型,前置 ++ 的效率高于后置 ++
  • ++ 操作符的重载规则和特性同样也适用于 -- 操作符

推荐阅读更多精彩内容