第40课 前置操作符和后置操作符
1. ++i和i++真的有区别吗?
(1)现代编译器会对代码进行优化
- 对于基础类型,前置++和后置++的汇编代码几乎是一样的,最终效率完全一样。
(2)优化使得最终的二进制程序更加高效
(3)优化后的二进制程序丢失了C/C++的原生语义
(4)不可能从编译后的二进制程序还原C/C++程序
【编程实验】真的有区别吗? 40-1.cpp
int i = 0; 013612FB mov dword ptr [i],0 i++; 01361302 mov eax,dword ptr [i] 01361305 add eax,1 01361308 mov dword ptr [i],eax ++i; 0136130B mov ecx,dword ptr [i] 0136130E add ecx,1 01361311 mov dword ptr [i],ecx
2. ++操作符的重载
(1)可利用全局函数和成员函数进行重载
(2)重载前置++操作符(如++i)不需要额外的参数
(3)重载后置++操作符(如i++)需要一个int类型的占位参数(即编译器通过有无这个占位符来区别是重载前置还是后置++操作符)
【编程实验】++操作符的重载 40-2.cpp
#include <iostream> using namespace std; class Test { int mValue; public: Test(int i){mValue = i;} int value(){return mValue;} //前置++(如++i),原生语义先自增后取值 //返回值为引用,无参! Test& operator ++() { ++mValue; //先自增 return *this;//后取值 } //后置++(如i++),原生语义先取值后自然 //返回值为对象,int型参数作占位符,以区别前置和后置++ Test operator ++(int) { Test ret(mValue); //先取值 mValue++; //后自增 return ret; //注意,这里返回自增之前的对象状态 } }; int main() { Test t(0); printf("t.value() = %d\n",(t++).value()); //0; //printf("t.value() = %d\n",(++t).value()); //1; return 0; }
运行结果:
3. 真正的区别
(1)对于基础类型的变量
①前置++的效率与后置++的效率基本相同
②根据项目组编码规范进行选择
(2)对于类类型的对象
①前置++的效率高于后置++
②尽量使用前置++操作符提高程序效率
【编程实验】复数类的进一步完善 Complex
//Complex.h
#ifndef _COMPLEX_H_ #define _COMPLEX_H_ 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& 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); //后置++ }; #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& c) { double na = a + c.a; double nb = b + c.b; return Complex(na, nb); } Complex Complex::operator - (const Complex& c) { double na = a - c.a; double nb = b - c.b; return Complex(na, nb); } Complex Complex::operator * (const Complex& c) { double na = a * c.a - b * c.b; double nb = a * c.b - b * c.a; return Complex(na, nb); } Complex Complex::operator / (const Complex& c) { double cm = c.a * c.a + c.b * c.b; double na = (a * c.a + b * c.b) / cm; double nb = (b * c.a - a * c.b) / cm; return Complex(na, nb); } bool Complex::operator == (const Complex& c) { return (a == c.a) && (b = c.b); } bool Complex::operator != (const Complex& c) { //整个复数对象就两个成员,如果这个2个对象的 //内存完全相等时,则两个复数相等 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; }
//main.cpp
#include <stdio.h>
#include "Complex.h"
int main()
{
Complex c1(0, 0);
Complex t1 = c1++;
Complex t2= ++c1;
printf("t1.a = %f, t1.b = %f\n",t1.getA(), t1.getB());//0, 0
printf("t2.a = %f, t2.b = %f\n",t2.getA(), t2.getB());//2, 2
return 0;
}
运行结果:
4. 小结
(1)编译优化使得最终的可执行程序更加高效
(2)前置++操作符和后置++操作符都可以被重载
(3)++操作符的重载必须符合其原生语义(即前置就先取值再自增,后置应先自增再取值)
- 对于基础类型,前置++与后置++的效率几乎相同
- 对于类类型,前置++的效率高于后置++