1、值得思考的问题
- 下面的代码有没有区别?为什么?
i++; // i的值作为返回值,i自增1
++i; // i自增1,i的值作为返回值

从反汇编我们可以看出,在工程里面,i++和++i这两行代码完全没有任何差异。原因在于这两行代码都是单行的代码,编译器就将它进行优化(为了高效),不使用返回值,因此这两行代码完全没有任何差异。
2、意想不到的事实
- 现代编译器产品会对代码进行优化
- 优化使得最终的二进制程序更加高效
- 优化后的二进制程序丢失了C/C++的原生语义
- 不可能从编译后的二进制程序还原C/C++程序
3、思考
++ 操作符可以重载吗?如何区分前置 ++ 和后置 ++?
4、++ 操作符的重载
- ++操作符可以被重载
— 全局函数和成员函数均可进行重载(推荐成员函数重载)
— 重载前置 ++ 操作符不需要额外的参数
— 重载后置 ++ 操作符需要一个 int 类型的占位参数
#include <iostream>
#include <string>
using namespace std;
class Test
{
private:
int i;
public:
Test(int i)
{
this->i = i;
}
Test& operator ++ ()
{
++i;
return *this;
}
Test operator ++ (int )
{
Test ret(i);
i++;
return ret;
}
int getI()
{
return i;
}
};
int main()
{
Test t(0);
cout << t.getI() << endl;
Test tt = ++t;
cout << t.getI() << endl;
cout << tt.getI() << endl;
cout << endl;
Test t1(0);
cout << t1.getI() << endl;
Test t2 = t1++;
cout << t1.getI() << endl;
cout << t2.getI() << endl;
return 0;
}

根据上面的分析:
前置++操作符的重载参数类型为空,返回值类型为类引用,原生语义是直接自增1,所以返回值类型必须要是类引用。
后置++操作符的重载参数需要一个占位参数 int,返回值类型为类类型,原生语义是先赋值,再自增1,所以返回值只要是类类型即可。
Test& operator ++ () //前置++操作符的重载
{
++i;
return *this;
}
Test operator ++ (int ) //后置++操作符的重载
{
Test ret(i);
i++;
return ret;
}
对于后置++操作符的重载,里面函数的内容很巧妙,先自定义一个局部对象 ret ,赋值为 i,i++后,返回原来的对象。
让我们回到最初的起点:
- 下面的代码有没有区别?为什么?
#include <iostream>
#include <string>
using namespace std;
class Test
{
private:
int i;
public:
Test(int i)
{
this->i = i;
}
Test& operator ++ ()
{
++i;
return *this;
}
Test operator ++ (int )
{
Test ret(i); //我只是用 i 来构造 ret
i++; //这个 i 和上面的 i 是没有关系的
return ret;
}
int getI()
{
return i;
}
};
int main()
{
Test t(0);
t++;
++t;
return 0;
}
第33行代码和第34行代码有差异吗?
我觉得有差异,因为他们调用的是完全不同的重载函数。效率上面也有差异,前置的++里面没有生成额外的对象,意味着不需要调用构造函数,也不需要调用析构函数,
而后置的++里面生成了一个局部对象,意味着需要调用构造函数,也需要调用析构函数。
所以这两条语句的效率有差别,和我们刚开始在C++代码看到的汇编代码而得出没有任何差异形成反差。
5、值得思考的问题
- 下面的代码有没有区别?为什么?这次我们应该如何回答?
i++; // i的值作为返回值,i自增1
++i; // i自增1,i的值作为返回值
真正的区别:
- 对于基础类型的变量
— 前置++的效率和后置++的效率基本相同
— 根据项目组编码规范进行选择 - 对于类类型的对象
— 前置++的效率高于后置++
— 尽量使用前置++操作符提高程序效率
—— 完善复数类:
Complex.h
#ifndef _COMPLEX_H_
#define _COMPLEX_H_
#pragma once
class Complex
{
private:
double a;
double b;
public:
Complex(double a = 0, double b = 0);
double getA();
double getB();
double getModulus();
Complex operator + (const Complex& p);
Complex operator - (const Complex& p);
Complex operator * (const Complex& p);
Complex operator / (const Complex& p);
bool operator == (const Complex& p);
bool operator != (const Complex& p);
Complex& operator = (const Complex& p);
Complex& operator ++ ();
Complex operator ++ (int);
};
#endif
Complex.cpp
#include "Complex.h"
#include <math.h>
Complex::Complex(double a, double b)
{
this->a = a;
this->b = b;
}
double Complex::getA()
{
return a;
}
double Complex::getB()
{
return b;
}
double Complex::getModulus()
{
return sqrt(a*a + b*b);
}
Complex Complex::operator + (const Complex& p)
{
double pa = a + p.a;
double pb = b + p.b;
Complex ret(pa, pb);
return ret;
}
Complex Complex::operator - (const Complex& p)
{
double pa = a - p.a;
double pb = b - p.b;
Complex ret(pa, pb);
return ret;
}
Complex Complex::operator * (const Complex& p)
{
double pa = a * p.a - b * p.b;
double pb = a * p.b + b * p.a;
Complex ret(pa, pb);
return ret;
}
Complex Complex::operator / (const Complex& p)
{
double pc = p.a * p.a + p.b * p.b;
double pa = (a * p.a + b * p.b) / pc;
double pb = (b * p.a - a * p.b) / pc;
Complex ret(pa, pb);
return ret;
}
bool Complex::operator == (const Complex& p)
{
return (a == p.a) && (b == p.b);
}
bool Complex::operator != (const Complex& p)
{
return (!(*this == p));
}
Complex& Complex::operator = (const Complex& p)
{
if (*this != p)
{
a = p.a;
b = p.b;
}
return *this;
}
Complex& Complex::operator ++ ()
{
a = a + 1;
b = b + 1;
return *this;
}
Complex Complex::operator ++ (int)
{
Complex ret(a, b);
a = a + 1; //成员变量
b = b + 1;
return ret;
}
main.cpp
#include <iostream>
#include "Complex.h"
using namespace std;
int main()
{
Complex c0(0, 0);
Complex c1 = ++c0;
cout << c0.getA() << endl;
cout << c0.getB() << endl;
cout << c1.getA() << endl;
cout << c1.getB() << endl;
cout << endl;
Complex c(0, 0);
Complex c2 = c++;
cout << c.getA() << endl;
cout << c.getA() << endl;
cout << c2.getB() << endl;
cout << c2.getB() << endl;
return 0;
}

小结:
- 编译优化使得最终的可执行程序更加高效
- 前置++操作符和后置++操作符都可以被重载
- ++操作符的重载必须符合原生语义
- 对于基础类型,前置++与后置++的效率几乎相同
- 对于类类型,前置++效率高于后置++
#include <iostream>
using namespace std;
class Test
{
private:
int i;
public:
Test(int i)
{
this->i = i;
}
int getI()
{
return i;
}
Test& operator++()
{
this->i++;
return *this;
}
Test operator++(int)
{
Test ret(i);
this->i++;
return ret;
}
};
int main()
{
Test t(2);
Test t1 = ++t;
cout << t1.getI() << endl;
return 0;
}
本文深入探讨C++中前置++与后置++操作符的重载实现,解析其背后的编译优化机制及对程序效率的影响。通过实例代码,对比不同情况下两种操作符的性能差异,特别强调在类类型对象上使用前置++操作符以提升效率。
1090

被折叠的 条评论
为什么被折叠?



