值得思考的问题
- 下面的代码有没有区别?为什么?
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
小结
- 编译优化使得最终的可执行程序更加高效
- 前置 ++ 操作符和后置 ++ 操作符都可以被重载
- ++ 操作符的重载必须符合原生语义
- 对于基础类型, 前置 ++ 与 后置 ++ 的效率几乎相同
- 对于类类型,前置 ++ 的效率高于后置 ++
以上内容参考狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。