C++学习笔记----8、掌握类与对象(六)---- 操作符重载(2)

1.3、第三次尝试:全局operator+

        隐式转换允许你使用operator+成员函数给SpreadsheetCell对象加上int与double。然而,这个操作符不是双向的,如下代码所示:

	aThirdCell = myCell + 5.6;
	aThirdCell = myCell + 4;
	aThirdCell = 5.6 + myCell; // FAILS TO COMPILE!
	aThirdCell = 4 + myCell;   // FAILS TO COMPILE!

        当SpreadsheetCell对象在操作符左侧的时候可以很好地进行隐式转换,但是当在右边的时候就不灵光了。另外假定是双向的,其实也有问题。问题就是operator+成员函数必须在SpreadsheetCell对象上进行调用,该对象必须在operator+的左手边。c++语言就是这么定义的。所以是没有办法让operator+成员函数按那种方式工作的。

        然而,如果把类内的operator+成员函数用全局的operator+函数替换,不与任何特定对象紧密绑定在一起,就可以解决这个问题了。函数看起来像这样:

SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
	return SpreadsheetCell { lhs.getValue() + rhs.getValue() };
}

        需要在模块接口文件中声明该操作符并export出来:

export class SpreadsheetCell
{
    /* Omitted for brevity */
};

export SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);

        现在所有的四个前面的相加操作都可以按你想要的结果工作了。

	aThirdCell = myCell + 5.6;    // works fine
	aThirdCell = myCell + 4;    // works fine
	aThirdCell = 5.6 + myCell; // works fine
	aThirdCell = 4 + myCell;   // works fine

        你可能会想,如果按下面的代码写会有什么结果:

aThirdCell = 4.5 + 5.5;

        它会正常编译并执行,但是不会调用你写的operator+。它会执行正常的double相加4.5与5.5,结果是下面的中间语句:

aThirdCell = 10;

        为了使这个赋值语句好好干活,应该在右手边有一个SpreadsheetCell对象。编译器发现有一个非显式的用户定义的构造函数使用一个double参数,会使用这个构造函数隐式地将double值转换成一个临时的SpreadsheetCell对象,然后会调用赋值操作符。

2、重载算术操作符

        现在你理解了怎么写operator+,那剩下的基本算术操作术就很直接了。下面是+,-,*,与/的声明,可以用<op>来替换+,-,*,与/,结果就是四个函数。也可以重载%,但是对于保存在SpreadsheetCell中的double值是讲不通的,没必要凑数了。

export class SpreadsheetCell { /* Omitted for brevity */ };
export SpreadsheetCell operator<op>(const SpreadsheetCell& lhs,
    const SpreadsheetCell& rhs);

        operator-与operator*的实现与operator+的实现类似,所以就不赘述了。对于operaotr/,稍有点儿不同,记住要检查是否被零除。如果检测到被零除要抛出一个例外:

SpreadsheetCell operator/(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
	if (rhs.getValue() == 0) {
		throw invalid_argument { "Divide by zero." };
	}
	return SpreadsheetCell { lhs.getValue() / rhs.getValue() };
}

                c++不要求在operator*真正实现乘,在operator/中实现除,等等。你可以在operator/中实现乘,在operator/中实现除,等等。然而,那样会非常地令人迷惑,没有道理这么做啊。只要有可能,在实现中用通常的用过的操作符的意思就行了。

注意:在c++中,不要改变操作的运算优先级。例如,*与/要比+与-早检查。一旦运算的优先级定了,用户定义的操作符唯一需要做的事就是去实现。c++也不允许你发明新的操作符号或者改变操作符的参数数量。我们以后还会再详细讨论操作符重载。

2.1、重载算术缩写操作符

        除了简单的算术操作符,c++提供了像+=与-=这样的缩写操作符。你可能想当然地认为在类中写了operator+,它就会提供operator+=。对不起,你没有这么走运。你不得不显式地重载缩写算术操作符。这些操作符与基本的算术操作述不同,它们改变了操作符左手边的对象而不是生成一个新对象。第二个细微的不同是,与赋值操作符相似,它们产生了一个指向被改变对象的引用结果。

        算术缩写操作符总是要求左手边的类的对象,所以要把它们写成成员函数,而不是全局函数。下面是SpreadsheetCell类的定义:

export class SpreadsheetCell
{
public:
	SpreadsheetCell& operator+=(const SpreadsheetCell& rhs);
	SpreadsheetCell& operator-=(const SpreadsheetCell& rhs);
	SpreadsheetCell& operator*=(const SpreadsheetCell& rhs);
	SpreadsheetCell& operator/=(const SpreadsheetCell& rhs);
    // Omitted for brevity
}

        operator+=的实现,其它的类似。

SpreadsheetCell& SpreadsheetCell::operator+=(const SpreadsheetCell& rhs)
{
	set(getValue() + rhs.getValue());
	return *this;
}

        缩写的算术操作符是基本算术与赋值操作符的组合。有了前面的定义,你可以写出下面的代码:

	SpreadsheetCell myCell { 4 }, aThirdCell{ 2 };
	aThirdCell -= myCell;
	aThirdCell += 5.4;

        但是,你不能写出下面这样的代码(有这种想法也是很奇葩!)

5.4 += aThirdCell;

        注意:当同时有正常的与缩写版本的某个操作符时,推荐使用正常的那个而不是缩写版本的,以避免代码重复。

        下面是一个例子:

SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
	auto result{ lhs };  // Local copy
	result += rhs;       // Forward to +=()
	return result;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java复制查询数组-cnblog

java数组 复制数组 copyOf(待复制数组,复制后新数组的长度) 如果复制后数组的长度&#xff0c;长于原来数组&#xff0c;多出来的元素会被补0&#xff0c;如果新数组元素少会从第一个元素&#xff0c;取到指定元素长度 package nb;import java.util.Arrays;public class co…

行业预测 60TB 硬盘将于 2028 年到来

在硬盘容量增长停滞了一段时间后&#xff0c;在短短四年内从目前的 30TB 增长到 60TB 将是一个巨大的增长。 然而&#xff0c;这正是 IEEE 最新发布的《海量数据存储设备和系统国际路线图》报告所预测的。 该路线图预计 2028 年市场上将出现 60TB 的硬盘驱动器。 这一增长将由一…

Flet介绍:平替PyQt的好用跨平台Python UI框架

随着Python在各个领域的广泛应用&#xff0c;特别是在数据科学和Web开发领域&#xff0c;对于一个简单易用且功能强大的用户界面&#xff08;UI&#xff09;开发工具的需求日益增长。传统的Python GUI库如Tkinter、PyQt虽然功能强大&#xff0c;但在易用性和现代感方面略显不足…

计算机毕业设计 | SpringBoot 房屋租赁网 租房买房卖房平台(附源码)

1&#xff0c;绪论 1.1 背景调研 在房地产行业持续火热的当今环境下&#xff0c;房地产行业和互联网行业协同发展&#xff0c;互相促进融合已经成为一种趋势和潮流。本项目实现了在线房产平台的功能&#xff0c;多种技术的灵活运用使得项目具备很好的用户体验感。 这个项目的…

Authentication Lab | Client Side Auth

关注这个靶场的其它相关笔记&#xff1a;Authentication Lab —— 靶场笔记合集-CSDN博客 0x01&#xff1a;Client Side Auth 前情提要 有些时候&#xff0c;开发人员会将身份验证的逻辑写于前端&#xff0c;这样写是十分不安全的&#xff0c;因为前端的代码几乎全部都是可见的…

C#多线程基本使用和探讨

线程是并发编程的基础概念之一。在现代应用程序中&#xff0c;我们通常需要执行多个任务并行处理&#xff0c;以提高性能。C# 提供了多种并发编程工具&#xff0c;如Thread、Task、异步编程和Parallel等。 Thread 类 Thread 类是最基本的线程实现方法。使用Thread类&#xff0…

快递查询软件:实现单号识别与批量物流查询的高效工具

随着网络购物的普及&#xff0c;快递物流行业迎来了前所未有的发展机遇&#xff0c;同时也面临着巨大的挑战。跟踪物流信息成为一个难题&#xff0c;因此&#xff0c;快递查询软件的核心功能之一便是单号识别。传统的快递单号输入方式繁琐且易出错在此背景下&#xff0c;快递查…

代码随想录day22:回溯part4

491.递增子序列 class Solution {List<List<Integer>> result new ArrayList<>();List<Integer> path new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}priv…

如何基于 RLHF 来优化 ChatGPT 类型的大语言模型

&#x1f6b4;前言 对于ChatGPT来说&#xff0c;RLHF是其训练的核心。所谓RLHF&#xff0c;即Reinforcement Learning with Human Feedback&#xff0c;基于人类反馈的强化学习。这项技术通过结合模型自身的生成能力和人类专家的反馈&#xff0c;为改进文本生成质量提供了新的…

计算机网络-------重传、TCP流量控制、拥塞控制

重传、滑动窗口、流量控制、拥塞避免 重传机制 超时重传 发送方在发送数据时会启动一个定时器&#xff0c;当超过指定的时间之后&#xff0c;还没接收到接收方的ACK确认应答报文&#xff0c;就会重传该数据 快重传 当发送方收到接收方三个连续的ack之后说明发送方发送的报…

关于Amazon Linux 2023的版本及包管理器

在亚马逊上创建EC2实例时&#xff0c;会看到有一个Amazon Linux镜像。 那这个镜像与其他Linux有什么关系和区别呢&#xff1f; 网站是介绍&#xff1a;Amazon Linux 2023 是基于 Linux 的现代化通用操作系统&#xff0c;提供 5 年的长期支持。它针对 AWS 进行了优化&#xff0…

《Linux从小白到高手》理论篇:深入理解Linux的计划任务/定时任务

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。本篇详细深入介绍Linux的计划任务/定时计划。 Linux的计划任务 在很多时候为了自动化管理系统&#xff0c;我们都会用到计划任务&#xff0c;比如关机&#xff0c;重启&#xff0c;备份之类…

详解Java中的BIO、NIO、AIO

1、 详解Java中的BIO、AIO、NIO 1.1、引言 IO流是Java中比较难理解的一个知识点&#xff0c;但是IO流在实际的开发场景中经常会使用到&#xff0c;比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO&#xff1a;BIO、NIO以及AIO&#xff0c;重点介绍NIO。…

读数据工程之道:设计和构建健壮的数据系统03数据工程生命周期(上)

1. 数据工程生命周期 1.1. 数据领域正在经历新数据技术和实践的爆炸式增长&#xff0c;抽象程度和易用性不断提高 1.2. 由于技术抽象程度的增加&#xff0c;数据工程师将越来越多地成为数据生命周期工程师&#xff0c;根据数据生命周期管理的原则来进行思考和操作 1.3. 数据…

专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结

目录 搜索 vs 深度优先遍历 vs 深度优先搜索 vs 宽度优先遍历 vs 宽度优先搜索 vs 暴搜 1.深度优先遍历 vs 深度优先搜索(dfs) 2.宽度优先遍历 vs 宽度优先搜索(bfs) 2.关系图暴力枚举一遍所有的情况 3.拓展搜索问题全排列 决策树 1. 计算布尔⼆叉树的值&#xff08;medi…

yub‘s Algorithmic Adventures_Day7

环形链表 link&#xff1a;https://leetcode.cn/problems/linked-list-cycle-ii/description/ 思路分析 我只能说双指针yyds【刻板hh】 我们分两种情况来分析 起码在第二圈才会相遇 fast比slow多走环的整数倍 fast 走的步数是 slow 步数的 2 倍&#xff0c;即 f2s&#xff…

计算机的错误计算(一百一十七)

摘要 算式“(5^25*(1/25)^(1/5)*3^25(1/25)^(1/5)*5^25*3^(251/5)-(9/25)^(1/5)*3^25*5^25-(1/25)^(1/5)*3^25*5.0^25*(13^(1/5)-3^(2/5.0)))” 的准确值是0. 但是&#xff0c;Python 与 Excel 均输出了错误结果&#xff1a;一个含有15位整数&#xff0c;一个含有14位整数。 …

Python | Leetcode Python题解之第464题我能赢吗

题目&#xff1a; 题解&#xff1a; class Solution:def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:cachedef dfs(usedNumbers: int, currentTotal: int) -> bool:for i in range(maxChoosableInteger):if (usedNumbers >> i) & 1…

初学者如何快速入门人工智能

一、引言 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;&#xff0c;作为当今科技领域极具前景与影响力的方向之一&#xff0c;吸引着众多人士投身其中。无论是对科技充满好奇的学生&#xff0c;还是意图拓展职业发展路径的职场人士&#xff0c…

网络知识_001_浏览器输入域名

文章目录 网络模型IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;网络地址&#xff0c;广播地址&#xff0c;NAT转换浏览器输入域名到网页打开发生了什么DNS获取顺序 网络模型 模型协议工具报文添加信息作用应用层http&#xff0c;https&#xff0c;ftp&#xff0c;…