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

news/2023/12/9 8:30:26 标签: c/c++

值得思考的问题

  • 下面的代码有没有区别?为什么?
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://www.niftyadmin.cn/n/1818937.html

相关文章

Json and Go

Reference https://blog.go-zh.org/json-a... Encoding Encode的基本用法是 package mainimport ("encoding/json""fmt""os" )type Message struct {Name stringBody stringTime int64 }func main() {message : Message{"Tom", "…

最大全0/1子矩阵

我们常常会遇到这样的问题&#xff1a;给定一个01矩阵&#xff0c;求其中全0/1的最大子矩阵的面积。 简单的模板题如&#xff1a;[Luogu]P4147&#xff0c;复杂点的有[Luogu]P5300 下面我们介绍一种比较容易的算法&#xff1a;悬线法 其实悬线法更多的是一种思想&#xff0c;许…

HBase指南 | HBase 2.0之修复工具HBCK2运维指南

目前社区已经发布了HBase的2.0版本&#xff0c;很多公司都希望去尝试新版本上的新功能&#xff0c;但是不得不面对的问题就是当集群出了问题应该如何解决。 在之前的HBase版本中&#xff0c;我们可以依赖hbck来帮助检查问题和修复问题&#xff0c;在新的版本上我们应该如何去处…

ROC-RK3308-CC开发实例总结--MPU6050运动处理传感器模块调试

传感器介绍MPU60X0是invenSence公司的一款全球首例9轴运动处理传感器。它内部集成了3轴MEMS陀螺仪和3轴MEMS加速度计&#xff0c;同时可以通过I2C接口&#xff08;注意这个接口是XDA、XCL&#xff0c;而开发板与MPU6050通信的接口是SDA、SCL&#xff09;连接一个第三方的数据传…

ECS Linux服务器xfs磁盘扩容

ECS Linux服务器xfs磁盘扩 ECS Linux服务器xfs磁盘使用阿里云官方提供的磁盘扩容方法扩容会有报错&#xff1a; [rootiZ28u04wmy2Z ~]# e2fsck /dev/xvdb1 e2fsck 1.42.9 (28-Dec-2013) ext2fs_open2: Bad magic number in super-block e2fsck: Superblock invalid, trying bac…

why’s kafka so fast

As we all know that Kafka is very fast, much faster than most of its competitors. So what’s the reason here? Avoid Random Disk Access Kafka writes everything onto the disk in order and consumers fetch data in order too. So disk access always works sequen…

简明高效的 Java 并发编程学习指南

你好&#xff0c;我是宝令&#xff0c;《Java 并发编程实战》专栏作者&#xff0c;很高兴你能看到这篇内容。 对于一个Java程序员而言&#xff0c;能否熟练掌握并发编程是判断他优秀与否的重要标准之一。因为并发编程是Java语言中最为晦涩的知识点&#xff0c;它涉及操作系统、…

Mybatis级联

在客观世界中&#xff0c;对象很少是孤独存在的&#xff0c;如班级与学生之间的关系&#xff0c;它们的实例之间可以互相访问&#xff0c;这就是关联关系。那么映射到数据库中就是表与表之间的关联关系&#xff08;级联&#xff09;&#xff0c;数据库中表常见的关联关系一般有…

数据治理六要素

引言&#xff1a; 帆软作为全球数据分析和商业智能平台提供商&#xff0c;这几年深刻的感受到了全球数据应用的热潮&#xff0c;但是随着越来越多的客户开始实施并广泛应用BI系统&#xff0c;数据治理的话题也在最近被越来越多地提及和讨论。 过去的十年&#xff0c;银行的IT系…

【C++】 46_继承中的构造与析构

思考&#xff1a;如何初始化父类成员&#xff1f;父类构造函数和子类构造函数有什么关系&#xff1f; 子类对象的构造 子类对象可以定义构造函数 子类构造函数 必须对继承而来的成员进行初始化 直接通过初始化列表或者赋值的方式进行初始化调用父类构造函数进行初始化父类构造函…

毕业生的纪念礼物

毕业生的纪念礼物 题目描述 现在有n个纪念品&#xff0c;每个纪念品都有一个种类r[i]&#xff0c;现在要求对每个毕业生分发三个种类不同的纪念品&#xff0c;现在需要你来计算下共可以发给多少个毕业生&#xff1f;输入 第一行一个整数n&#xff0c;1≤n≤100000&#xff0c;代…

Jenkins研究

Jenkins研究1. 简介Jenkins是一个开源软件项目。在企业的软件构建过程中&#xff0c;JAVA的应用工程稍显复杂&#xff0c;由于复杂构建、和代码上线、并且服务的重启。整个过程下来&#xff0c;消耗的时间较多&#xff0c;Jenkins却能很好的集成maven的编译方式&#xff0c;且…

01 面向对象之:初识

一、面向对象初识 1.1 回顾面向对象编程vs函数式编程 # 面向过程编程 测量对象的元素个个数。 s1 fjdsklafsjda count 0 for i in s1:count 1l1 [1,2,3,4] count 0 for i in l1:count 1 面向过程编程def func(s):count 0for i in s:count 1return count func(fdsafdsa)…

tensorflow 出现 tensorflow.python.framework.errors_impl.NotFoundError(dataset_ops.so not found)...

2019独角兽企业重金招聘Python工程师标准>>> 运行环境 Windows 10Python3.6Tensorflow 1.9.0错误代码 tf.add_to_collection(losses, tf.contrib.layers.l2_regularizer(regularizer)(w)) 出现错误 tensorflow.python.framework.errors_impl.NotFoundError: D:\User…

git hub 资源记录

GitHub 上的开发资源大全系列Java 资源大全 http://t.cn/RUtp4qtPython 资源大全 http://t.cn/Rq0C0ETJS 资源大全 http://t.cn/R44bazjCSS 资源大全 http://t.cn/R4trAbciOS 资源大全 http://t.cn/Rbe5h16Android 资源大全 http://t.cn/RtJsQydC 资源大全 http://t.cn/…

读懂属性描述符

属性描述符 我们定义的对象&#xff0c;对应的每一个属性都对应一个‘属性描述符’对象&#xff0c;用来描述该属性的一些特性&#xff1a; 属性描述符有两种形式&#xff1a;数据描述符或存取描述符。数据描述符是一个具有值的属性&#xff0c;该值可能是可写的&#xff0c;也…
最新文章