C++Primer学习(14.1 基本概念)

当运算符作用于类类型的运算对象时,可以通过运算符重载重新定义该运算符的含义。明智地使用运算符重载能令我们的程序更易于编写和阅读。举个例子,因为在Sales_item类中定义了输入、输出和加法运算符,所以可以通过下述形式输出两个Sales_item的和:

cout << item1 + item2;//输出两个Sales item的和

相反的,由于我们的sales_data类还没有重载这些运算符,因此它的加法代码显得比较冗长而不清晰:

print(cout,add(data1,data2));//输出两个Sales data的和

14.1 基本概念
重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成。和其他函数一样,重载的运算符也包含返回类型、参数列表以及函数体。
重载运算符函数的参数数量与该运算符作用的运算对象数量一样多。一元运算符有一个参数,二元运算符有两个。对于二元运算符来说,左侧运算对象传递给第一个参数,而右侧运算对象传递给第二个参数。除了重载的函数调用运算符operator()之外,其他重载运算符不能含有默认实参。
如果一个运算符函数是成员函数,则它的第一个(左侧)运算对象绑定到隐式的this指针上,因此,成员运算符函数的(显式)参数数量比运算符的运算对象总数少一个。
Note:当一个重载的运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数的(显式)参数数量比运算对象的数量少一个。
对于一个运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数:

//错误:不能为int 重定义内置的运算符
int operator+(intint);

这一约定意味着当运算符作用于内置类型的运算对象时,我们无法改变该运算符的含义。
我们可以重载大多数(但不是全部)运算符。表14.1指明了哪些运算符可以被重载,哪些不行。我们将在19.1.1节(第726页)介绍重载new和delete的方法。
我们只能重载已有的运算符,而无权发明新的运算符号。例如,我们不能提供operator**来执行幂操作。
有四个符号(+、-、*、&)既是一元运算符也是二元运算符,所有这些运算符都能被重载,从参数的数量我们可以推断到底定义的是哪种运算符。
对于一个重载的运算符来说,其优先级和结合律与对应的内置运算符保持一致。不考虑运算对象类型的话,
X == y + Z; 永远等价于x==(y+z)。
在这里插入图片描述
直接调用一个重载的运算符函数
通常情况下,我们将运算符作用于类型正确的实参,从而以这种间接方式“调用”重载的运算符函数。然而,我们也能像调用普通函数一样直接调用运算符函数,先指定函数名字,然后传入数量正确、类型适当的实参:

//一个非成员运算符函数的等价调用
data1 + data2;//普通的表达式
operator+(datal,data2);//等价的函数调用

这两次调用是等价的,它们都调用了非成员函数operator+,传入 data1作为第一个实参、传入 data2作为第二个实参。
我们像调用其他成员函数一样显式地调用成员运算符函数。具体做法是,首先指定运行函数的对象(或指针)的名字,然后使用点运算符(或箭头运算符)访问希望调用的函数:

data1+= data2;//基于“调用”的表达式
data1.operator+=(data2);//对成员运算符函数的等价调用

这两条语句都调用了成员函数 operator+=,将this 绑定到 data1的地址、将 data2作为实参传入了函数。
某些运算符不应该被重载
回忆之前介绍过的,某些运算符指定了运算对象求值的顺序。因为使用重载的运算符本质上是一次函数调用,所以这些关于运算对象求值顺序的规则无法应用到重载的运算符上。特别是,逻辑与运算符、逻辑或运算符和逗号运算符的运算对象求值顺序规则无法保留下来。除此之外,&&和||运算符的重载版本也无法保留内置运算符的短路求值属性,两个运算对象总是会被求值。
因为上述运算符的重载版本无法保留求值顺序和/或短路求值属性,因此不建议重载它们。当代码使用了这些运算符的重载版本时,用户可能会突然发现他们一直习惯的求值规则不再适用了。
还有一个原因使得我们一般不重载逗号运算符和取地址运算符:C++语言已经定义了这两种运算符用于类类型对象时的特殊含义,这一点与大多数运算符都不相同。因为这两种运算符已经有了内置的含义,所以一般来说它们不应该被重载,否则它们的行为将异于常态,从而导致类的用户无法适应。
BestPrntices 通常情况下,不应该重载逗号、取地址、逻辑与和逻辑或运算符。
使用与内置类型一致的含义
当你开始设计一个类时,首先应该考虑的是这个类将提供哪些操作。在确定类需要哪些操作之后,才能思考到底应该把每个类操作设成普通函数还是重载的运算符。如果某些操作在逻辑上与运算符相关,则它们适合于定义成重载的运算符:
(1)如果类执行I0操作,则定义移位运算符使其与内置类型的I0保持一致。
(2)如果类的某个操作是检查相等性,则定义operator==;如果类有了operator==,意味着它通常也应该有operator!=。
(3)如果类包含一个内在的单序比较操作,则定义operator<;如果类有了operator<,则它也应该含有其他关系操作。
(4)重载运算符的返回类型通常情况下应该与其内置版本的返回类型兼容:逻辑运算符和关系运算符应该返回 bool,算术运算符应该返回一个类类型的值,赋值运算符和复合赋值运算符则应该返回左侧运算对象的一个引用。
提示:尽量明智地使用运算符重载
每个运算符在用于内置类型时都有比较明确的含义。以二元+运算符为例,它明显执行的是加法操作。因此,把二元+运算符映射到类类型的一个类似操作上可以极大地简化记忆。例如对于标准库类型string来说,我们就会使用+把一个string对象连接到另一个后面,很多编程语言都有类似的用法。
当在内置的运算符和我们自己的操作之间存在逻辑映射关系时,运算符重载的效果最好。此时,使用重载的运算符显然比另起一个名字更自然也更直观。不过,过分滥用运算符重载也会使我们的类变得难以理解。
在实际编程过程中,一般没有特别明显的滥用运算符重载的情况。例如,一般来说没有哪个程序员会定义operator+并让它执行减法操作。然而经常发生的一种情况是,程序员可能会强行扭曲了运算符的“常规”含义使得其适应某种给定的类型,这显然是我们不希望发生的。因此我们的建议是:只有当操作的含义对于用户来说清晰明了时才使用运算符。如果用户对运算符可能有几种不同的理解,则使用这样的运算符将产生二义性。
赋值和复合赋值运算符
赋值运算符的行为与复合版本的类似:赋值之后,左侧运算对象和右侧运算对象的值相等,并且运算符应该返回它左侧运算对象的一个引用。重载的赋值运算应该继承而非违背其内置版本的含义。
如果类含有算术运算符或者位运算符,则最好也提供对应的复合赋值运算符。无须言,+=运算符的行为显然应该与其内置版本一致,即先执行+,再执行=。
选择作为成员或者非成员
当我们定义重载的运算符时,必须首先决定是将其声明为类的成员函数还是声明为一个普通的非成员函数。在某些时候我们别无选择,因为有的运算符必须作为成员:另一些情况下,运算符作为普通函数比作为成员更好
下面的准则有助于我们在将运算符定义为成员函数还是普通的非成员函数做出抉择:
(1)赋值(=)、下标([])、调用(())和成员访问箭头(->)运算符必须是成员。
(2)复合赋值运算符一般来说应该是成员,但并非必须,这一点与赋值运算符略有不同。
(3)改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减和解引用运算符,通常应该是成员。
(4)具有对称性的运算符可能转换任意一端的运算对象,例如算术、相等性、关系和位运算符等,因此它们通常应该是普通的非成员函数。
程序员希望能在含有混合类型的表达式中使用对称性运算符。例如,我们能求一个int和一个double的和,因为它们中的任意一个都可以是左侧运算对象或右侧运算对象,所以加法是对称的。如果我们想提供含有类对象的混合类型表达式,则运算符必须定义成非成员函数
当我们把运算符定义成成员函数时,它的左侧运算对象必须是运算符所属类的一个对象。例如:

string s="world";
string t=s+"!"; //正确:我们能把一个const char*加到一个string 对象中
string u="hi"+s;//如果+是string的成员,则产生错误

如果 operator+是 string 类的成员,则上面的第一个加法等价于s.operator+(“!”)。同样的,“hi”+s等价于"hi".operator+(s)。显然"hi"的类型是const char*,这是一种内置类型,根本就没有成员函数。
因为string将+定义成了普通的非成员函数,所以"hi"+s等价于operator+(“hi”,s)。和任何其他函数调用一样,每个实参都能被转换成形参类型。唯一的要求是至少有一个运算对象是类类型,并且两个运算对象都能准确无误地转换成string。

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

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

相关文章

计算机视觉准备八股中

一边记录一边看&#xff0c;这段实习跑路之前运行完3DGAN&#xff0c;弄完润了&#xff0c;现在开始记忆八股 1.CLIP模型的主要创新点&#xff1a; 图像和文本两种不同模态数据之间的深度融合、对比学习、自监督学习 2.等效步长是每一步操作步长的乘积 3.卷积层计算输入输出…

基于大语言模型的智能音乐创作系统——从推荐到生成

一、引言&#xff1a;当AI成为音乐创作伙伴 2023年&#xff0c;一款由大语言模型&#xff08;LLM&#xff09;生成的钢琴曲《量子交响曲》在Spotify冲上热搜&#xff0c;引发音乐界震动。传统音乐创作需要数年专业训练&#xff0c;而现代AI技术正在打破这一壁垒。本文提出一种…

Mysql---锁篇

1&#xff1a;MySQL 有哪些锁&#xff1f; 全局锁 flush tables with read lock 整个数据库就处于只读状态了 unlock tables 释放全局锁 全局锁主要应用于做全库逻辑备份&#xff0c;这样在备份数据库期间&#xff0c;不会因为数据或表结构的更新&#xff0c;而出现备份文件的数…

VLAN综合实验二

一.实验拓扑&#xff1a; 二.实验需求&#xff1a; 1.内网Ip地址使用172.16.0.0/分配 2.sw1和SW2之间互为备份 3.VRRP/STP/VLAN/Eth-trunk均使用 4.所有Pc均通过DHCP获取IP地址 5.ISP只能配置IP地址 6.所有…

GEO(生成引擎优化)实施策略全解析:从用户意图到效果追踪

——基于行业实证的AI信源占位方法论 ​一、理解用户查询&#xff1a;构建AI语料的核心起点 生成式AI的内容推荐逻辑以用户意图为核心&#xff0c;​精准捕捉高频问题是GEO优化的第一步。企业需通过以下方法挖掘用户真实需求&#xff1a; ​AI对话日志分析&#xff1a; 分析用…

HTML基础及进阶

目录 一、HTML基础 1.什么是HTML 2.常用标签 &#xff08;1&#xff09;标题标签&#xff1a;h1-h6数字越小文字会越大&#xff0c;这个标签会占一整行 &#xff08;2&#xff09;加粗标签&#xff1a; &#xff08;3&#xff09;换行标签&#xff1a; &#xff08;4&am…

MSTP与链路聚合技术

MSTP&#xff08;多生成树协议&#xff09; 简介 MSTP&#xff08;多生成树协议&#xff09;是Spanning Tree Protocol&#xff08;STP&#xff09;的改进版&#xff0c;支持网络中使用多条生成树&#xff0c;并根据用户需求限制生成树间的路径。MSTP将多个VLAN映射到一棵生成…

ModuleNotFoundError: No module named ‘ml_logger.logbook‘

问题 (legion) zhouy24RL-DSlab:~/zhouy24Files/legion/LEGION$ python main.py ML_LOGGER_USER is not set. This is required for online usage. Traceback (most recent call last): File “main.py”, line 7, in from mtrl.app.run import run File “/data/zhouy24File…

c# ftp上传下载 帮助类

工作中FTP的上传和下载还是很常用的。如下载打标数据,上传打标结果等。 这个类常用方法都有了:上传,下载,判断文件夹是否存在,创建文件夹,获取当前目录下文件列表(不包括文件夹) ,获取当前目录下文件列表(不包括文件夹) ,获取FTP文件列表(包括文件夹), 获取当前目…

PyTorch 分布式训练(Distributed Data Parallel, DDP)简介

PyTorch 分布式训练&#xff08;Distributed Data Parallel, DDP&#xff09; 一、DDP 核心概念 torch.nn.parallel.DistributedDataParallel 1. DDP 是什么&#xff1f; Distributed Data Parallel (DDP) 是 PyTorch 提供的分布式训练接口&#xff0c;DistributedDataPara…

策略模式_行为型_GOF23

策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;核心思想是将一组算法封装成独立对象&#xff0c;使它们可以相互替换&#xff0c;从而让算法的变化独立于使用它的客户端。这类似于游戏中的技能切换——玩家根据战况选择不同技能…

【Python】天气数据可视化

1. Python进行数据可视化 在数据分析和科学计算领域&#xff0c;Python凭借其强大的库和简洁的语法&#xff0c;成为了众多开发者和科研人员的首选工具。数据可视化作为数据分析的重要环节&#xff0c;能够帮助我们更直观地理解数据背后的规律和趋势。本文将详细介绍如何使用P…

深度学习4.4笔记

《动手学深度学习》-4.4-笔记 验证数据集&#xff1a;通常是从训练集中划分出来的一部分数据&#xff0c;不要和训练数据混在一起&#xff0c;评估模型好坏的数据集 测试数据集&#xff1a;只用一次的数据集 k-折交叉验证&#xff08;k-Fold Cross-Validation&#xff09;是…

vue 两种路由模式

一、两种模式比较 在vue.js中&#xff0c;路由模式分为两种&#xff1a;hash 模式和 history 模式。这两种模式决定了URL的结构和浏览器历史记录的管理方式。 1. hash 模式带 #&#xff0c;#后面的地址变化不会引起页面的刷新。换句话说&#xff0c;hash模式不会将#后面的地址…

Android生态大变革,谷歌调整开源政策,核心开发不再公开

“开源”这个词曾经是Android的护城河&#xff0c;如今却成了谷歌的烫手山芋。最近谷歌宣布调整Android的开源政策&#xff0c;核心开发将全面转向私有分支。翻译成人话就是&#xff1a;以后Android的核心更新&#xff0c;不再公开共享了。 这操作不就是开源变节吗&#xff0c;…

JavaScript中集合常用操作方法详解

JavaScript中集合常用操作方法详解 JavaScript中的集合主要包括数组(Array)、集合(Set)和映射(Map)。下面我将详细介绍这些集合类型的常用操作方法。 数组(Array) 数组是JavaScript中最常用的集合类型&#xff0c;提供了丰富的操作方法。 创建数组 // 字面量创建 const ar…

【HC-05】蓝牙串口通信模块调试与应用(1)

一、HC-05 基础学习视频 HC-05蓝牙串口通信模块调试与应用1 二、HC-05学习视频课件

【学Rust写CAD】18 定点数2D仿射变换矩阵结构体(MatrixFixedPoint结构别名)

源码 // matrix/fixed.rs use crate::fixed::Fixed; use super::generic::Matrix;/// 定点数矩阵类型别名 pub type MatrixFixedPoint Matrix<Fixed, Fixed, Fixed, Fixed, Fixed, Fixed>;代码解析 这段代码定义了一个定点数矩阵的类型别名 MatrixFixedPoint&#xff…

axios文件下载使用后端传递的名称

java后端通过HttpServletResponse 返回文件流 在Content-Disposition中插入文件名 一定要设置Access-Control-Expose-Headers&#xff0c;代表跨域该Content-Disposition返回Header可读&#xff0c;如果没有&#xff0c;前端是取不到Content-Disposition的&#xff0c;可以在统…

HarmonyOS之深入解析如何根据url下载pdf文件并且在本地显示和预览

一、文件下载 ① 网络请求配置 下载在线文件&#xff0c;需要访问网络&#xff0c;因此需要在 config.json 中添加网络权限&#xff1a; {"module": {"requestPermissions": [{"name": "ohos.permission.INTERNET","reason&qu…