乐趣区

【C++】 40_前置操作符和后置操作符

值得思考的问题
下面的代码有没有区别?为什么?
void code()
{
int i = 0;

i++; // i 的值作为返回值,i 自增 1
++i; // i 自增 1,i 作为返回值
}
编程实验:真的有区别吗?
#include <iostream>

using namespace std;

int main()
{
int i = 0;

i++;

++i;

return 0;
}
vc++ 2010 汇编
int i = 0;
0127136E mov dword ptr [i],0

i++;
01271375 mov eax,dword ptr [i]
01271378 add eax,1
0127137B mov dword ptr [i],eax

++i;
0127137E mov eax,dword ptr [i]
01271381 add eax,1
01271384 mov dword ptr [i],eax
g++ 汇编
14 int i = 0;
0804869d: movl $0x0,0x1c(%esp)
16 i++;
080486a5: addl $0x1,0x1c(%esp)
18 ++i;
080486aa: addl $0x1,0x1c(%esp)
对于基础数据类型,在工程上没有任何区别。由于实例中没有使用返回值,经过编译器优化后,生成相同的汇编代码。
意想不到的事实

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

C/C++ 开发的软件无法完全反编译
思考:++ 操作符可以重载吗?如何区分前置 ++ 和后置 ++?
++ 操作符重载

++ 操作符可以被重载

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

编程实验:++ 操作符的重载
#include <iostream>

using namespace std;

class Test
{
private:
int mValue;
public:
Test(int i)
{
mValue = i;
}

int value()
{
return mValue;
}

Test& operator ++ ()
{
mValue = mValue + 1;

return *this;
}

Test operator ++ (int) // 返回值而不是引用
{
Test ret(mValue);

mValue = mValue + 1;

return ret;
}
};

int main()
{
Test t1(0);
Test t2(0);

Test tt1 = t1++;
cout << t1.value() << endl;
cout << tt1.value() << endl;

Test tt2 = ++t2;
cout << t2.value() << endl;
cout << tt2.value() << endl;

return 0;
}
输出:
1
0
1
1

后置 ++ 操作符重载分析:
Test operator ++ (int)
{
Test ret(mValue);

mValue = mValue + 1;

return ret;
}

在栈空间创建对象
调用构造函数
调用析构函数

真正的区别

对于基础类型的变量

前置 ++ 的效率与后置 ++ 的效率基本相同
根据项目组编码规范进行选择

对于类类型的对象

前置 ++ 的效率高于后置 ++
尽量使用前置 ++ 操作符提高程序效率

编程实验:复数类的进一步完善
Complex.h
#ifndef _COMPLEX_H_
#define _COMPLEX_H_

class Complex
{
private:
double a;
double b;

public:
Complex(int a = 0, int b = 0);
int getA();
int getB();
int getModulus();

Complex operator + (const Complex& c);
Complex operator – (const Complex& c);
Complex operator * (const Complex& c);
Complex operator / (const Complex& c);

bool operator == (const Complex& c);
bool operator != (const Complex& c);

Complex& operator = (const Complex& c);

Complex& operator ++ ();
Complex operator ++ (int);
Complex& operator — ();
Complex operator — (int);
};

#endif
Complex.cpp
#include “Complex.h”
#include <math.h>

Complex::Complex(int a, int b)
{
this->a = a;
this->b = b;
}

int Complex::getA()
{
return a;
}

int Complex::getB()
{
return b;
}

int Complex::getModulus()
{
return sqrt(a * a + b * b);
}

Complex Complex::operator + (const Complex& c)
{
double na = a + c.a;
double nb = b + c.a;
Complex ret(na, nb);

return ret;
}

Complex Complex::operator – (const Complex& c)
{
double na = a – c.a;
double nb = b – c.b;
Complex ret(na, nb);

return ret;
}

Complex Complex::operator * (const Complex& c)
{
double na = a * c.a – b * c.b;
double nb = a * c.b + b * c.a;
Complex ret(na, nb);

return ret;
}

Complex Complex::operator / (const Complex& c)
{
double nm = c.a * c.a + c.b * c.b;
double na = (a * c.a + b * c.b) / nm;
double nb = (b * c.a – a * c.b) / nm;
Complex ret(na, nb);

return ret;
}

bool Complex::operator == (const Complex& c)
{
return (a == c.a) && (b == c.b);
}

bool Complex::operator != (const Complex& c)
{
return !(*this == c);
}

// 为了实现循环赋值,将自身引用返回
Complex& Complex::operator = (const Complex& c)
{
// 若意图自己给自己赋值,则跳过
if(this != &c)
{
a = c.a;
b = c.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;
}

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 c1(0, 0);
Complex c2(0, 0);

Complex c3 = c1++;

cout << c3.getA() << endl;
cout << c3.getB() << endl;

Complex c4 = ++c2;

cout << c4.getA() << endl;
cout << c4.getB() << endl;

return 0;
}
输出:
0
0
1
1

小结

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

以上内容参考狄泰软件学院系列课程,请大家保护原创!

退出移动版