首页 > 代码库 > 第四十课、前置操作符和后置操作符

第四十课、前置操作符和后置操作符

一、i++和++i有没有区别?

1.现代编译器产品会对代码进行优化

2.优化使得最终二进制程序更加高效

3.优化后的二进制程序丢失了c/c++的原生语义

4.不可能从编译后的二进制程序还原c/c++程序

 

 //由此可知,单行的i++和++i在汇编层的代码完全一样  
int i = 0; 0123136E mov dword ptr [i],0 i++; 01231375 mov eax,dword ptr [i] 01231378 add eax,1 0123137B mov dword ptr [i],eax ++i; 0123137E mov eax,dword ptr [i] 01231381 add eax,1 01231384 mov dword ptr [i],eax

 

二、++操作符的重载

1、全局函数成员函数均可进行重载

2、重载前置++操作符不需要额外的参数

3、重载后置的++操作符需要一个int类型的占位参数编译器以此来分辨是前置还是后置操作符

 

#include<iostream>

using namespace std;

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

    int Value()
    {
        return m_value;
    }
    //前置操作符,原生语义先自增,再将自增后的值作为返回值
  //返回值为引用,无参数 Test
& operator ++ () { ++m_value; return *this; }
  //后置操作符,原生语义为先返回值,再增1
  //返回值为对象,有一个int类型的占位参数 Test
operator ++ (int) { Test ret(m_value);//先保存原来的值,需要另外创建对象,所有在这里比前置操作符效率低
m_value
++;//后自增
return ret; } }; int main() { Test t0(0); Test t1(1); cout<< (t0++).Value() <<endl; //0 cout<< t0.Value() <<endl; //1 cout<< (++t1).Value() <<endl; //2 return 0; }

三、真正的区别

1、对于基础类型的变量

(1)、前置++的效率与后置++的效率基本相同

(2)、根据项目组编程规范进行选择

2、对于类类型的变量

(1)、前置++的效率高于后置++

(2)、尽量使用前置++操作符提高程序效率

四、复数类的进一步完善

//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;
}

五、小结

1、编译优化使得最终可执行程序更加高效

2、前置操作符后置操作符都可以重载

3、++操作符的重载必须符合它的原生语义

4、对于基础类型,前置++与后置++效率几乎相同

5、对于类类型,前置++效率高于后置++

 

第四十课、前置操作符和后置操作符