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.rhkb.cn/news/43281.html

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

相关文章

循相似之迹:解锁协同过滤的核心推荐逻辑

目录 一、引言二、协同过滤的基本原理三、协同过滤的算法类型&#xff08;一&#xff09;基于用户的协同过滤&#xff08;二&#xff09;基于物品的协同过滤 四、协同过滤的应用案例&#xff08;一&#xff09;电商平台的商品推荐&#xff08;二&#xff09;音乐平台的歌曲推荐…

RuoYi基础学习

1 若依搭建 前后端分离版本&#xff1a;RuoYi-Vue利用SpringBoot作为后端开发框架&#xff0c;与Vue.js结合&#xff0c;实现了前后端分离的开发模式。这种架构有助于提高开发效率&#xff0c;前后端可以独立开发和部署&#xff0c;更适合现代化的Web应用开发。 RuoYi-Vue3&a…

Docker 安装部署Harbor 私有仓库

Docker 安装部署Harbor 私有仓库 系统环境:redhat x86_64 一、首先部署docker 环境 定制软件源 wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repoyum install -y yum-utils device-mapper-persistent-data lvm2…

【Basys3】外设-灯和数码管

灯 约束文件 set_property PACKAGE_PIN W5 [get_ports CLK] set_property PACKAGE_PIN U18 [get_ports rst] set_property PACKAGE_PIN U16 [get_ports {led[0]}] set_property PACKAGE_PIN E19 [get_ports {led[1]}] set_property PACKAGE_PIN U19 [get_ports {led[2]}] set…

【Django】教程-1-安装+创建项目+目录结构介绍

欢迎关注我&#xff01;后续会更新django教程。一周2-3更&#xff0c;欢迎跟进&#xff0c;本周会更新第一个Demo的单独一个模块的增删改查【Django】教程-4-一个增删改查的Demo【Django】教程-2-前端-目录结构介绍【Django】教程-3-数据库相关介绍 1.项目创建 1.1 安装 Djan…

蓝桥杯 之 二分

文章目录 习题肖恩的n次根分巧克力2.卡牌 二分是十分重要的一个算法&#xff0c;常常用于求解一定范围内&#xff0c;找到满足条件的边界值的情况主要分为浮点数二分和整数二分二分问题&#xff0c;最主要是写出这个check函数&#xff0c;这个check函数最主要就是使用模拟的方法…

SpringBoot集成腾讯云OCR实现身份证识别

OCR身份证识别 官网地址&#xff1a;https://cloud.tencent.com/document/product/866/33524 身份信息认证&#xff08;二要素核验&#xff09; 官网地址&#xff1a;https://cloud.tencent.com/document/product/1007/33188 代码实现 引入依赖 <dependency><…

2025年3月电子学会c++五级真题

结绳 #include <bits/stdc.h> using namespace std;int n,a[10010];int main() {cin>>n;for(int i 0;i<n;i){cin>>a[i];}sort(a0,an);//将a数组从小到大排序double sum 0;for(int i 0;i<n;i){sum (suma[i])/2;}cout<<(int)sum;return 0; } 最…

Typora使用Gitee作为图床

Typora使用Gitee作为图床 文章目录 Typora使用Gitee作为图床Gitee准备图床仓库下载安装软件安装插件 配置Typora Gitee准备图床仓库 新建一个仓库右上角下拉->设置->安全设置->私人令牌->生成新令牌&#xff0c;注意将令牌保存&#xff08;只会出现一次&#xff0…

QT音乐播放器(1):数据库保存歌曲

实现功能&#xff1a;用数据库保存本地导入和在线搜索的歌曲记录 目录 一. 保存本地添加的歌曲 1. 使用QSettings &#xff08;1&#xff09;在构造函数中&#xff0c;创建对象。 &#xff08;2&#xff09;在导入音乐槽函数中&#xff0c;保存新添加的文件路径&#xff0c…

SQLAlchemy关键词搜索技术深度解析:从基础过滤到全文检索

在数据驱动的应用开发中&#xff0c;基于关键词的模糊查询是常见的业务需求。SQLAlchemy作为Python生态中最流行的ORM框架&#xff0c;提供了多种实现关键词搜索的技术方案。本文将从性能、适用场景和技术复杂度三个维度&#xff0c;系统对比分析SQLAlchemy中关键词搜索的最佳实…

css属性列举

介绍 CSS word-spacing 属性&#xff0c;用于指定段字之间的空间&#xff0c;例如&#xff1a; p {word-spacing:30px; }word-spacing属性增加或减少字与字之间的空白。 注意&#xff1a; 负值是允许的。 浏览器支持 表格中的数字表示支持该属性的第一个浏览器版本号。 属…

python实现股票数据可视化

最近在做一个涉及到股票数据清洗及预测的项目&#xff0c;项目中需要用到可视化股票数据这一功能&#xff0c;这里我与大家分享一下股票数据可视化的一些基本方法。 股票数据获取 在经过多次尝试后&#xff0c;发现了一个

从 JDK 11 到 JDK 17:OpenRewrite 实战 Spring Boot 升级指南

一、为什么选择 OpenRewrite 升级&#xff1f; 在 Spring Boot 项目升级 JDK 的过程中&#xff0c;我们面临两个核心痛点&#xff1a; 语法兼容性问题&#xff08;如废弃的 API、新的关键字&#xff09;依赖版本冲突&#xff08;特别是 Spring Boot 与 JDK 版本的匹配&#x…

交换技术综合实验

一、实验拓扑 二、实验要求 内网IP地址使用172.16.0.0/16分配。 SW1和SW2之间互为备份。 VRRP/STP/VLAN/Eth-trunk均使用。 所有PC通过DHCP获取IP地址。 ISP只能配置IP地址。 所有电脑可以正常访问ISP路由器。 三、实验步骤 基于172.16.0.0/16进行划分 172.16.2.0/24&…

【Linux】了解基础指令(超详细)

目录 【whoami】指令【pwd】指令【mkdir】指令【touch】指令【ls】指令文件的扩展内容 【cd】指令相对路径和绝对路径(.和..存在的原因)绝对路径相对路径 【rm】指令【man】命令【less】指令echo指令重定向操作追加重定向 cat 指令输入重定向 管道操作(组合指令)查找三剑客find…

基于改进粒子群算法的多目标分布式电源选址定容规划(附带Matlab代码)

通过分析分布式电源对配电网的影响&#xff0c;以有功功率损耗、电压质量及分布式电源总容量为优化目标&#xff0c;基于模糊理论建立了分布式电源在配电网中选址定容的多目标优化模型&#xff0c;并提出了一种改进粒子群算法进行求解。在算例仿真中&#xff0c;基于IEEE-14标准…

26_ajax

目录 了解 接口 前后端交互 一、安装服务器环境 nodejs ajax发起请求 渲染响应结果 get方式传递参数 post方式传递参数 封装ajax_上 封装ajax下 了解 清楚前后端交互就可以写一些后端代码了。小项目 现在写项目开发的时候都是前后端分离 之前都没有前端这个东西&a…

OJ题:移动零

双指针法 c 语言实现 void moveZeroes(int* nums, int numsSize) {int dest,cur; //创建临时指针和目标指针destcur0;//出初始化while(cur<numsSize)//遍历{if(nums[cur]!0){swap(&nums[cur],&nums[dest]);cur;dest;}else{cur;}}} 思路是建立两个指针&#xff0…