第40课 前置操作符和后置操作符

1. ++i和i++真的有区别吗?

(1)现代编译器会对代码进行优化。对于基础类型,前置++和后置++的汇编代码几乎是一样的,最终效率完全一样

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

(3)优化后的二进制程序丢失了C/C++的原生语义

(4)不可能从编译后的二进制程序还原C/C++程序。

    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类型的占位参数。(即编译器通过有无这个占位符来区别是重载前置还是后置++操作符)

【编程实验】++操作符的重载

#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)对于类类型的对象

  ①前置++的效率高于后置++

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

【编程实验】复数类的进一步完善

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

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

4. 小结

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

(2)前置++操作符和后置++操作符都可以被重载

(3)++操作符的重载必须符合其原生语义(即前置就先取值再自增,后置应先自增再取值)

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

(5)对于类类型,前置++的效率高于后置++

时间: 2024-12-12 12:31:48

第40课 前置操作符和后置操作符的相关文章

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

一.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 [

C++中前置操作符和后置操作符的重载

1,C 语言中讨论了原生含义,C++ 中有必要考虑前置.后置操作符能够重载,有何问题: 2,值得思考的问题: 1,下面的代码有没有区别?为什么? 1,i++  // i 的值作为返回值,i 自增 1: 2,++i  // i 自增 1,i 的值作为返回值: 3,没有使用返回值,由于编译器(不同的编译器都是一样的)的优化,在工程上面,这两行代码没有区别: 2,真的有区别吗?编程实验: 1,main.cpp 文件: 1 #include <iostream> 2 #include <stri

C++--前置操作符与后置操作符

一.前置操作符与后置操作符 Q:下面的代码有没有区别?为什么?代码的实现 #include <iostream> #include <string> using namespace std; int main() { int i = 0; i++; ++i; return 0; } 意想不到的事实1.现代编译器都会对代码进行优化2.优化使得最终的二进制程序更加高效3.优化后的二进制程序丢失了C/C++的原生语义4.不可能从编译后的二进制程序还原C/C++程序 Q:++操作符可以重载

前置操作符 后置操作符

++操作符的重载 1.全局函数和成员函数都可以进行重载. 2.前置++操作符不需要参数. 3.后置++操作符需要int类型的占位参数(区分前置后置). #include <iostream> #include <string> using namespace std; class Test { int mValue; public: Test(int i) { mValue = i; } int value() { return mValue; } Test& operat

Thinkphp入门 二 —空操作、空模块、模块分组、前置操作、后置操作、跨模块调用(46)

原文:Thinkphp入门 二 -空操作.空模块.模块分组.前置操作.后置操作.跨模块调用(46) [空操作处理] 看下列图: 实际情况:我们的User控制器没有hello()这个方法 一个对象去访问这个类不存在的方法,那么它会去访问”魔术方法__call()” 用户访问一个不存在的操作—>解决:给每个控制器都定义个_empty()方法来处理 第二个解决方法:定义一个空操作 [空模块处理] 我们使用一个类,但是现在这个类还没有被include进来. 我们可以通过自动加载机制处理__autoloa

thinkPHP 空模块和空操作、前置操作和后置操作 具体介绍(十四)

本章节:介绍 TP 空模块和空操作.前置操作和后置操作 具体介绍 一.空模块和空操作 1.空操作 function _empty($name){ $this->show("$name 不存在 <a href='__APP__/Index/index'>返回首页</a>"); } 2.空模块(EmptyAction.class.php的文件) class EmptyAction extends Action{ function index(){ //$thi

thinkPHP 空模块和空操作、前置操作和后置操作 详细介绍(十四)

本章节:介绍 TP 空模块和空操作.前置操作和后置操作 详细介绍 一.空模块和空操作 1.空操作 function _empty($name){ $this->show("$name 不存在 <a href='__APP__/Index/index'>返回首页</a>"); } 2.空模块(EmptyAction.class.php的文件) class EmptyAction extends Action{ function index(){ //$thi

[原创]java WEB学习笔记106:Spring学习---AOP的通知 :前置通知,后置通知,返回通知,异常通知,环绕通知

1.通知分类: @Before: 前置通知, 在方法执行之前执行 @After: 后置通知, 在方法执行之后执行 @AfterRunning: 返回通知, 在方法返回结果之后执行 @AfterThrowing: 异常通知, 在方法抛出异常之后 @Around: 环绕通知, 围绕着方法执行 关于方法签名 看第五点 2.前置通知 3.后置通知:在后置通知中,不能访问目标方法执行的结果          4.返回通知               5.异常通知 6.环绕通知 1 package com.

Spring aop——前置增强和后置增强 使用注解Aspect和非侵入式配置

AspectJ是一个面向切面的框架,它扩展了java语言,定义了AOP语法,能够在编译期提供代码的织入,所以它有一个专门的编译器用来生成遵守字节码字节编码规范的Class文件 确保使用jdk为5.0以上版本. 01.使用注解标注增强(AspectJ)  :取代了配置文件中的aop:pointcut节点的配置 添加jar和log4j的配置文件 aspectj-1.8.7.jar aspectjweaver.jar 添加头文件: xmlns:aop="http://www.springframewo