CPP 核心编程4-重载递增运算符

news2024/10/5 17:28:02

在这里插入图片描述
在这里插入图片描述

#include "iostream"

using namespace std;

//递增运算符重载
//自定义整型
class MyInteger {
    friend ostream &operator<<(ostream &cout, MyInteger mi);

public:
    MyInteger() {
        m_Num = 0;
    }

    //重置前置++运算符  返回引用是为了对同一个数进行操作
    MyInteger &operator++() {//这里不能返回值MyInteger 必须返回MyInteger&  因为操作的需要是都一个对象,返回值就是拷贝了
        //先进行++运算
        m_Num++;
        //再将自身作返回
        return *this;
    }
    //重置后置++运算符

private:
    int m_Num;
};

//重载左移运算符
ostream &operator<<(ostream &cout, MyInteger mi) {
    cout << mi.m_Num;
    return cout;
}

void test() {
    MyInteger mi;
    cout << ++(++mi) << endl;//C++里面原生的前置递增可以链式调用,后置递增不可以链式调用
}

int main() {
//    test();
    //C++里面原生的前置递增可以链式调用,后置递增不可以链式调用
    int a = 0;
    ++(++a);
    cout << a << endl;//输出2
    return 0;
}
2

后置递增
C++里面后置++是不能链式调用的

#include "iostream"

using namespace std;

//递增运算符重载
//自定义整型
class MyInteger {
    friend ostream &operator<<(ostream &cout, MyInteger mi);

public:
    MyInteger() {
        m_Num = 0;
    }

    //重置前置++运算符  返回引用是为了对同一个数进行操作
    MyInteger &operator++() {//这里不能返回值MyInteger 必须返回MyInteger&  因为操作的需要是都一个对象,返回值就是拷贝了
        //先进行++运算
        m_Num++;
        //再将自身作返回
        return *this;
    }

    //重置后置++运算符   !!!!!!之前学习的占位符终于找到用武之地了
    //返回值用const修饰,他能防止一些问题,例如: (p++)++
    const MyInteger operator++(int) {//int 代表占位参数,可以用于区分前置和后置递增,这里只能是int,double等不好使
        MyInteger temp = *this;
        m_Num++;
        return temp;
    }

private:
    int m_Num;
};

//重载左移运算符
ostream &operator<<(ostream &cout, MyInteger mi) {
    cout << mi.m_Num;
    return cout;
}

void test() {
    MyInteger mi;
//    cout << ++(++mi) << endl;
    cout << mi++ << endl;//输出0   //返回值用const修饰,他能防止一些问题,例如: (p++)++
    cout << mi << endl;//输出1
}

int main() {
    test();
    return 0;
}
0
1

递增运算符分为前置递增和后置递增。这两个分开来说吧。
前置递增。
需要创建一个名字叫做 人 的类,这个类中有一个 年龄 属性,且默认值为0,然后类外重载左移运算符方便打印输出。我们对人类的对象进行递增操作就是想让年龄增加。如下:

#include <iostream>
using namespace std;

class Person
{
public:
int age = 0;
Person& operator++()//**1**
{
age += 1;
return *this;
}
};
ostream& operator<<(ostream& cout, const Person &p)
{
cout << p.age;
return cout;
}
void test1()
{
Person p;
cout << "++p = " << ++p << endl;
cout << "++(++p) = " << ++(++p) << endl;
cout << "p = " << p << endl;
}
int main()
{
test1();
system("pause");
return 0;
}

第一个问题 :返回值为什么是引用?
答案:因为前置递增运算符可以这样使用:++(++p)。即进行两次连续的递增操作。若返回值为一个对象,则会产生一个匿名对象,之后++操作是对匿名独对象进行++操作。结果如下:
第二个问题 :为什么这是前置递增,不应该是后置递增吗?
首先解释一下问题,还是举个例子吧。
加运算符在类内实现重载的写法:Person operator+(Person &p);
当你调用的时候,如:p1 + p2,其本质调用是 p1.operator+(p2); 。你会发现,是 +号前面的对象调用函数,加号后面的对象是参数 。所以,当我们调用Person& operator++();的时候,是不是应该写 p1++??
答案:(个人推测)可能和后置递增有关。为了区分前置和后置。

在这里插入图片描述

后置递增。
第一个问题 :是后置递增类内重载的写法遇到的问题:
返回值和参数都是啥??想这样写??

Person operator++();
Person& operator++();
Person operator++(Person& p);
....

想了好久,也没想出来该怎么写。
答案:const Person operator++(int)
其中int的作用是占位符,为了和前置递增区分开来,而且只能写int,写double、float等都是不行的。因为没有这个占位参数的话,该函数与前置递增就只有返回值不同了,而返回值是不可以作为函数重载的条件的。
至于返回值的为什么是Person话,而且还用const修饰,在下一个问题中说明。
第二个问题 具体是怎样实现的,毕竟后置递增和前置递增还是有区别的。
答案:

const Person operator++(int)
{
Person p = *this;
age += 1;
return p;
}

首先创建一个临时的对象,用来保存当前值,因为该函数最后返回的不是递增后的结果,而是递增之前的值。
然后,属性加一,完成递增操作。
最后,返回临时对象
注意1: 此时的temp是一个临时对象,该函数运行结束后就会被编译器回收,所以我们直接返回temp的引用。我们需要进行值返回,值返回的话会调用拷贝构造函数重新创建一个对象。
注意2: 返回值用const修饰,他能防止一些问题,例如: (p++)++ 。我们可以做一个小测试。

int p = 0;
cout << "(p++)++ = " << (p++)++ << endl;
cout << "p = " << p << endl;

我们预想的结果可能是输出:(p++)++ = 1 p = 2
但实际结果是这样的:
报错了,原因是++需要可修改的左值。从结果我们可以知道,表达式p++的结果是不允许被修改的,所以我们后置递增的返回值是const类型的。
那么为什么会这样呢?
同样举个例子:
在这里插入图片描述

int p;
cout << "p = " << p << endl;
cout << "p++ = " << p++ << endl;
cout << "p = " << p << endl;

运行结果如下:
我们输出 p++ 的结果是0,这个0是哪里来的呢??是变量p中存储的吗??并不是,此时p中存储的值已经被改变了,这个0是产生的一个临时值。这个临时值在内存中的位置是未知的,我们无法对其进行修改。
所以,当我们 (p++)++ 这样使用后置递增运算符的时候,相当于尝试修改临时变量的值,这是不被允许的。
所以,我们重载递增操作符的返回值要用const来修饰。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/64084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LSTM内部结构及前向传播原理——LSTM从零实现系列(1)

一、前言 作为专注于时间序列分析的玩家&#xff0c;虽然LSTM用了很久但一直没有写过一篇自己的LSTM原理详解&#xff0c;所以这次要写一个LSTM的从0到1的系列&#xff0c;从模型原理讲解到最后不借助三方框架自己手写代码来实现LSTM模型。本文本身没有特别独到之处&#xff0c…

Vue学习:el 与data的两种写法

el两种写法 法一&#xff1a;建立了联系 <!-- 准备容器 --><div id"root"><h1>hello,{{name}} </h1> <!-- {{插值语法}} --></div><script>new Vue({ el: #root,data: {name:Amy},});</script> 法二&#xff1a…

论文投稿指南——中国(中文EI)期刊推荐(第1期)

&#x1f680; EI是国际知名三大检索系统之一&#xff0c;在学术界的知名度和认可度仅次于SCI&#xff01;&#x1f384;&#x1f388; 【前言】 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊。其中&#xf…

java计算机毕业设计ssm特大城市地铁站卫生防疫系统5i80c(附源码、数据库)

java计算机毕业设计ssm特大城市地铁站卫生防疫系统5i80c&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持…

UDS服务基础篇之14

前言 你知道如果系统产生了DTC&#xff0c;应当如何清除呢&#xff1f;14服务具体的执行流程如何&#xff1f;14服务在使用过程中的常见bug又有哪些&#xff1f; 这篇&#xff0c;我们来一起探索并回答这些问题。为了便于大家理解&#xff0c;以下是本文的主题大纲&#xff1…

相控阵天线(十二):天线校准技术仿真介绍之旋转矢量法

目录简介旋转矢量法算法介绍旋转矢量法校准对方向图的影响旋转矢量法算法仿真移相器位数对旋转矢量法的影响多通道旋转矢量法算法仿真分区旋转矢量法算法仿真简介 由于制造公差和天线互耦的影响&#xff0c;天线各通道会呈现出较大的幅相误差&#xff0c;因此需对天线进行校准…

光阑,像差和成像光学仪器

人眼 人眼成像过程 空气-角膜 水状液-晶状体 晶状体-玻璃体 三个界面的折射成像 瞳孔 2-8mm 可变光阑,调节入射光强弱 睫状肌 改变晶状体曲率---调焦 人眼的调节 远点—眼睛完全松弛状态下看清楚的最远点&#xff0c;正常眼的远点在无穷远 近点—睫状肌最大收缩(焦…

【Redis】解决全局唯一 id 问题

永远要记得坚持的意义 一、全局唯一 id 场景 概念&#xff1a; 以订单表的 id 为例 使用自增 id 会产生的问题&#xff1a; id 的规律性太明显&#xff0c;容易让用户猜测到一些信息受表单数据量的限制 —— 分布式存储时&#xff0c;会产生问题 &#xff08;自增长&#x…

讲理论,重实战!阿里内部SpringBoot王者晋级之路全彩小册开源

大家都知道&#xff0c;Spring Boot框架目前不仅是微服务框架的最佳选择之一&#xff0c;还是现在企业招聘人才肯定会考察的点&#xff1b;很多公司甚至已经将SpringBoot作为了必备技能。但&#xff0c;现在面试这么卷的情况下&#xff0c;很多人面试时还只是背背面试题&#x…

基于KDtree的电路故障检测算法的MATLAB仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 k-d树是每个节点都为k维点的二叉树。所有非叶子节点可以视作用一个超平面把空间分割成两个半空间。节点左边的子树代表在超平面左边的点&#xff0c;节点右边的子树代表在超平面右边的点。选择超…

企业数据安全如何落实?私有化知识文档管理系统效率部署

编者按&#xff1a;本文分析了数据安全性企业的重要性&#xff0c;特别是高保密企业单位&#xff0c;介绍了天翎知识文档管理群晖NA是如何保护企业数据安全的。 关键词&#xff1a;私有化部署&#xff0c;安全技术&#xff0c;数据备份&#xff0c;病毒防护&#xff0c;全网隔…

【zeriotier】win10安装zeriotier的辛酸泪

目录概述问题1&#xff1a;waiting for zeriotier system service问题2&#xff1a;Zerotier One 出现Node ID “unknown”问题3&#xff1a;一切正常&#xff0c;但是连不上服务器最终解决方法附录概述 背景&#xff1a;实验室的服务器是使用zeriotier组网的&#xff0c;因此…

字符串-模板编译

模板编译 编译就是一种格式转换成另一种格式的过程&#xff0c;这里主要讨论一下模板编译。模板字符串对比普通的字符串有很多的不同&#xff0c;模板字符串可以嵌套&#xff0c;并且模板字符串可以在内部使用${xxx}进行表达式运算以及函数调用&#xff0c;这些其实都是模板编…

DPDK Ring

无锁环ring是DPDK提供的一种较为基础的数据结构&#xff0c;其支持多生产者和多消费者同时访问。 经过我的经验&#xff0c;无锁结构的实现主要依靠两方面&#xff1a; 最终的数据交换一定要是原子级的操作&#xff0c;最常用到的自然就是比较后交换&#xff08;Compare And S…

Java项目:SSM个人博客网站管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目包含管理员与游客两种角色&#xff1b; 管理员角色包含以下功能&#xff1a; 发表文章,查看文章,类别管理,添加类别,个人信息管理,评论…

DeepSort目标跟踪算法

DeepSort目标跟踪算法是在Sort算法基础上改进的。 首先介绍一下Sort算法 Sort算法的核心便是卡尔曼滤波与匈牙利匹配算法 卡尔曼滤波是一种通过运动特征来预测目标运动轨迹的算法 其核心为五个公式&#xff0c;包含两个过程&#xff1a; 其分为先验估计&#xff08;预测&…

[附源码]计算机毕业设计人事管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

UE4中抛体物理模拟UProjectileMovementComponent

UE4中抛体物理模拟UProjectileMovementComponent1.简述2.使用方法3.绘制抛物曲线4.绘制抛物曲线1.简述 背景&#xff1a;实现抛体运动&#xff0c;反弹效果&#xff0c;抛物曲线等功能 通用实现可以使用spline绘制&#xff0c;物体按照下图接口可以根据时间更新位置 USplineC…

CN_MAC介质访问控制子层@CSMA协议

文章目录常用方法静态方法信道划分MAC特点动态方法随机访问MACCSMA协议CSMA/CD多点接入(或多点访问):载波监听Note:&#x1f388;碰撞检测碰撞:碰撞冲突过程传播时延对载波侦听的影响&#x1f388;争用期发现碰撞的最迟情况电磁波的速率是有限最短帧长&#x1f388;小结&#x…

CAD重复圆绘制机械图形

这次CAD必练图形第四个&#xff0c;这个图形主要用到了CAD圆、直线、修剪、旋转等多个命令&#xff0c;看着不简单&#xff0c;等绘制出来后就觉得还是挺简单的。 目标图形 操作步骤 1.使用CAD直线命令绘制一条水平的直线和四条垂直的直线&#xff0c;四条垂直的直线之间的距…