C++——运算符重载

一、运算符重载

①含义

函数重载或函数多态:同名函数完成相同的基本操作
C++将重载的概念扩展到运算符上,于是出现了运算符重载

C++中有很多运算符已经被重载
*运算符,运用于地址,可以得到存储在这个地址的值;运用于两个数字,得到是两个数字的乘积
C++会根据操作数的数目和类型来决定采用哪种操作
C++允许将运算符重载扩展到用户定义的类型中,例如类,允许使用+将两个对象相加

②格式

operatorop(argument-list)
例如:operator+()operator*()
其中op必须是一个有效的C++运算符,不能虚构,例如:operator@(),C++中没有@运算符

假设有一个Animal类有两个对象,dog和cat,并定义了operator+()成员函数重载+运算符,当两个对象相加时,编译器发现操作数都是Animal对象,则会使用相应的运算符函数来进行替换
animal = dog + cat;
animal = dog.operator+(cat);

二、实操举例

小明早上上班通勤花费2h35min,晚上下班通勤花费2h40min,则一天上下班共花费多少时间在通勤上?

Ⅰ重载常规做法

①time.h

定义一个Time类,当分钟超过59时,函数AddMinutes()和Sum()方法会使用整数除法和求模运算符进行调整

#pragma once
#ifndef TIME_H_
#define TIME_H_

class Time 
{
private:
	int hour_;
	int minute_;

public:
	Time();
	Time(int hours, int minutes);
	void AddMinutes(int minutes);
	void AddHours(int hours);
	void Reset(int hours = 0, int minutes = 0);
	Time Sum(const Time& time) const;
	void PrintTime() const;
};

#endif // !TIME_H_

②time.cpp

不要返回执行局部变量或临时对象的引用,函数执行完毕后,局部变量和临时对象都会消失,引用将指向不存在的数据
这里的Sum函数返回类型是Time,而非引用

#include <iostream>
#include "time.h"

Time::Time() 
{
	hour_ = 0;
	minute_ = 0;
}

Time::Time(int hour, int minute)
{
	hour_ = hour;
	minute_ = minute;
}

void Time::AddMinutes(int minutes) 
{
	minute_ += minutes;
	hour_ += minute_ / 60;
	minute_ %= 60;
}

void Time::AddHours(int hours) 
{
	hour_ += hours;
}

void Time::Reset(int hour, int minute) 
{
	hour_ = hour;
	minute_ = minute;
}


//Time,返回类型是Time,而不是引用;返回类型不能是引用,需要创建对象的副本;若为返回类型为引用时,sum对象是局部变量,函数结束会被删除
//const Time& t,参数是引用
Time Time::Sum(const Time& t) const
{
	Time sum;
	sum.minute_ = minute_ + t.minute_;
	sum.hour_ = hour_ + t.hour_ + sum.minute_ / 60;
	sum.minute_ %= 60;
	return sum;
}

void Time::PrintTime() const 
{
	std::cout << hour_ << ":" << minute_ << std::endl;
}

③main.cpp

#include <iostream>
#include "time.h"

int main() 
{
	Time go_to_work(2, 45);
	Time work_time(6, 30);
	Time go_home(3, 15);
	Time total_time;

	std::cout << "go_to_work time is: ";
	go_to_work.PrintTime();
	std::cout << std::endl;

	std::cout << "work_time time is: ";
	work_time.PrintTime();
	std::cout << std::endl;

	std::cout << "go_home time is: ";
	go_home.PrintTime();
	std::cout << std::endl;

	total_time = go_to_work.Sum(work_time.Sum(go_home));
	std::cout << "total_time is: ";
	total_time.PrintTime();
	std::cout << std::endl;

	return 0;
}

运行结果:
在这里插入图片描述
可以看到,上班通勤2h45min,工作6h30min,下班通勤3h15min,一天总用12h30min

Ⅱ重载加法运算符

常规做法看起来很麻烦
total_time = go_to_work.Sum(work_time.Sum(go_home));

不如直接使用重载加法运算符操作便捷
total_time = go_to_work + work_time + go_home;

重载加法运算符很简单,只需要将Sum()改成operator+()即可

①time.h

原先:Time Sum(const Time& time) const;
现在:Time operator+(const Time& time) const;

#pragma once
#ifndef TIME_H_
#define TIME_H_

class Time
{
private:
	int hour_;
	int minute_;

public:
	Time();
	Time(int hours, int minutes);
	void AddMinutes(int minutes);
	void AddHours(int hours);
	void Reset(int hours = 0, int minutes = 0);
	
	//Time Sum(const Time& time) const;
	Time operator+(const Time& time) const;
	
	void PrintTime() const;
};

#endif // !TIME_H_

②time.cpp

原先:Time Time::Sum(const Time& t) const
现在:Time Time::operator+(const Time& t) const

#include <iostream>
#include "time.h"

Time::Time() 
{
	hour_ = 0;
	minute_ = 0;
}

Time::Time(int hour, int minute)
{
	hour_ = hour;
	minute_ = minute;
}

void Time::AddMinutes(int minutes) 
{
	minute_ += minutes;
	hour_ += minute_ / 60;
	minute_ %= 60;
}

void Time::AddHours(int hours) 
{
	hour_ += hours;
}

void Time::Reset(int hour, int minute) 
{
	hour_ = hour;
	minute_ = minute;
}

/*
//Time,返回类型是Time,而不是引用;返回类型不能是引用,需要创建对象的副本;若为返回类型为引用时,sum对象是局部变量,函数结束会被删除
//const Time& t,参数是引用
Time Time::Sum(const Time& t) const
{
	Time sum;
	sum.minute_ = minute_ + t.minute_;
	sum.hour_ = hour_ + t.hour_ + sum.minute_ / 60;
	sum.minute_ %= 60;
	return sum;
}
*/
Time Time::operator+(const Time& t) const
{
	Time sum;
	sum.minute_ = minute_ + t.minute_;
	sum.hour_ = hour_ + t.hour_ + sum.minute_ / 60;
	sum.minute_ %= 60;
	return sum;
}


void Time::PrintTime() const 
{
	std::cout << hour_ << ":" << minute_ << std::endl;
}

③main.cpp

原先:total_time = go_to_work.Sum(work_time.Sum(go_home));
现在:total_time = go_to_work.operator+(work_time.operator+(go_home));
等价于:total_time1 = go_to_work + work_time + go_home;

在运算符表示法中,运算符左侧的对象(go_to_work )是调用对象,运算符右边的对象(work_time + go_home)是作为参数被传递的对象

+运算符是从左向右结合的运算符
首先work_time.operator+(go_home)返回一个Time对象,work_timego_home的和,然后这个和作为go_to_work.operator+()的参数,得到go_to_workwork_timego_home之和

#include <iostream>
#include "time.h"

int main() 
{
	Time go_to_work(2, 45);
	Time work_time(6, 30);
	Time go_home(3, 15);
	Time total_time, total_time1;

	std::cout << "go_to_work time is: ";
	go_to_work.PrintTime();
	std::cout << std::endl;

	std::cout << "work_time time is: ";
	work_time.PrintTime();
	std::cout << std::endl;

	std::cout << "go_home time is: ";
	go_home.PrintTime();
	std::cout << std::endl;

	//total_time = go_to_work.Sum(work_time.Sum(go_home));
	total_time = go_to_work.operator+(work_time.operator+(go_home));
	total_time1 = go_to_work + work_time + go_home;

	std::cout << "total_time is: ";
	total_time.PrintTime();
	std::cout << std::endl;

	std::cout << "total_time1 is: ";
	total_time1.PrintTime();
	std::cout << std::endl;

	return 0;
}

运行结果:
在这里插入图片描述

三、限制

看到这里,我想家人们应该会理解了,运算符重载其实就是这么一回事,没那么难
说白了就是operatorop去替代函数名称而已,例如operator+()替代Sum()

运算符重载理解了,家人们可以随意去发挥去秀操作,但运算符重载是有限制的

重载的运算符不必是成员函数,但必须至少有一个操作数是用户定义的类型!
使用运算符时不能反运算符原来的句法规则,例如不能将求模运算符(%)重载成使用一个操作数,例如int x; Time t; % x; % t;
同样不能修改运算符的优先级,若将+运算符重载为两个类相加,则新的运算符与原来的+具有相同的优先级

还有一些运算符不可以重载,家人们可以去网上搜索一下对应的表格

以下是不可重载的运算符和可重载的运算符

1,不可重载的运算符:
在这里插入图片描述
2,可重载的运算符
在这里插入图片描述

本篇博文参考《C++ Primer Plus(第6版)》若有侵权,联系立删

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

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

相关文章

抖去推碰一碰系统技术源码/open SDK转发技术开发

抖去推碰一碰系统技术源码/open SDK转发技术开发 碰一碰智能系统#碰碰卡系统#碰一碰系统#碰一碰系统技术源头开发 碰碰卡智能营销系统开发是一种集成了人工智能和NFC技术的工具&#xff0c;碰碰卡智能营销系统通过整合数据分析、客户关系管理、自动化营销活动、多渠道整合和个…

【Unity3D】ECS入门学习(六)状态组件 ISystemStateComponentData

当需要获知组件是否被销毁时&#xff0c;ECS是没有回调告知的&#xff0c;因此可以将组件继承于ISystemStateComponentData接口&#xff0c;这样即使组件的实体被销毁了&#xff0c;该组件本身是不会消失的&#xff0c;所以可以通过在组件实体销毁后&#xff0c;去设置状态组件…

期权懂|如何计算期权卖方平仓后的盈利?

锦鲤三三每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 如何计算期权卖方平仓后的盈利&#xff1f; 期权卖方平仓后的盈利计算涉及多个因素&#xff0c;包括期权的交易价格、平仓价格以及权利金的变动等。 交易价格&#xff1a;期权卖…

ARM64 Windows 10 IoT工控主板运行x86程序效率测试

ARM上的 Windows 10 IoT 企业版支持仿真 x86 应用程序&#xff0c;而 ARM上的 Windows 11 IoT 企业版则支持仿真 x86 和 x64 应用程序。英创推出的名片尺寸ARM64工控主板ESM8400&#xff0c;可预装正版Windows 10 IoT企业版操作系统&#xff0c;x86程序可无需修改而直接在ESM84…

【Ubuntu 20.4安装截图软件 flameshot 】

步骤一&#xff1a; 安装命令&#xff1a; sudo apt-get install flameshot 步骤二&#xff1a; 设置快捷方式&#xff1a; Ubuntu20.4 设置菜单&#xff0c;点击 号 步骤三&#xff1a; 输入软件名称&#xff0c; 软件快捷命令&#xff08;flameshot gui&#xff09;&am…

NAT 技术如何解决 IP 地址短缺问题?

NAT 技术如何解决 IP 地址短缺问题&#xff1f; 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 随着互联网的普及和发展&#xff0c;IP 地址的需求量迅速增加。尤其是 IPv4 地址&…

算法题(17):删除有序数组中的重复项

审题&#xff1a; 需要我们原地删除数组中的重复数据&#xff0c;并输出有效数据个数 思路&#xff1a; 方法一&#xff1a;原地解法&#xff08;双指针&#xff09; 设置left指针指向当前的非重复数据&#xff0c;right负责遍历数组&#xff0c;遇到和left指向的数据不同的数据…

LaTeXChecker:使用 Python 实现以主 TEX 文件作为输入的 LaTeX 检查和统计工具

使用 Python 实现以主 TEX 文件作为输入的 LaTeX 检查和统计工具&#xff0c;适用于包括但不限于一稿多模板的复杂排版方式&#xff0c;工具以只读模式运行。 Github 链接&#xff1a;https://github.com/BatchClayderman/LaTeXChecker import os from sys import argv, exec…

Web API和Web Services的区分

前些年一提及自动化测试&#xff0c;大多是指UI界面层的自动化测试。近几年&#xff0c;随着分层自动化测试概念的兴起&#xff0c;以及自动化测试自身的发展与细分&#xff0c;自动化测试包含了更多的内容。 API(Application ProgrammingInterface&#xff0c;应用程序编程接…

基于深度学习(HyperLPR3框架)的中文车牌识别系统-前言

参考链接&#xff1a; GitHub - szad670401/HyperLPR: 基于深度学习高性能中文车牌识别 High Performance Chinese License Plate Recognition Framework.基于深度学习高性能中文车牌识别 High Performance Chinese License Plate Recognition Framework. - szad670401/HyperL…

RAGFlow 基于深度文档理解构建的开源 RAG引擎 - 安装部署

RAGFlow 基于深度文档理解构建的开源 RAG引擎 - 安装部署 flyfish 1. 确保 vm.max_map_count ≥ 262144 这是指要调整Linux内核参数vm.max_map_count&#xff0c;以确保其值至少为262144。这个参数控制着进程可以映射的最大内存区域数量。对于某些应用程序&#xff08;如Ela…

QT:一个TCP客户端自动连接的测试模型

版本 1:没有取消按钮 测试效果&#xff1a; 缺陷&#xff1a; 无法手动停止 测试代码 CMakeLists.txt cmake_minimum_required(VERSION 3.19) project(AutoConnect LANGUAGES CXX)find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets Network)qt_standard_project_setup(…

(亲测)frp对外提供简单的文件访问服务-frp静态文件效果

话说有一天&#xff0c;希望将软件安装包放到网上&#xff0c;希望类似如下效果&#xff0c;正好在调试frp docker版&#xff0c;看到frp有个【对外提供简单的文件访问服务】功能&#xff0c;网上搜索也没相关效果图&#xff0c;所以顺手测试一下&#xff0c;截了几张图&#x…

一个简单的机器学习实战例程,使用Scikit-Learn库来完成一个常见的分类任务——**鸢尾花数据集(Iris Dataset)**的分类

机器学习实战通常是将理论与实践结合&#xff0c;通过实际的项目或案例&#xff0c;帮助你理解并应用各种机器学习算法。下面是一个简单的机器学习实战例程&#xff0c;使用Scikit-Learn库来完成一个常见的分类任务——**鸢尾花数据集&#xff08;Iris Dataset&#xff09;**的…

如何解决 ‘adb‘ 不是内部或外部命令,也不是可运行的程序或批处理文件的问题

在cmd中输入 adb &#xff0c;显示 ‘adc‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件的问题 解决办法&#xff1a;在环境变量中添加adb所在的路径 1、找到 adb.exe 的所在的文件路径&#xff0c;一般在 Android 安装目录下 \sdk\platform-tools\adb.exe…

【开源】一款基于SpringBoot的智慧小区物业管理系统

一、下载项目文件 项目文件源码链接&#xff1a;https://pan.quark.cn/s/3998d958e182如出现网盘空间不够存的情况&#xff01;&#xff01;&#xff01;解决办法是先用夸克手机app注册&#xff0c;然后保存上方链接&#xff0c;就可以得到1TB空间了&#xff01;&#xff01;&…

Linux编程(清华大学出版社2019年1月第1版)第7章-进程间通信-课后作业

7.1 输出: 4:ABCD 4:EFGH7.2 输出: numbers3 10 20 30 7.3 #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <limits.h> #include <fcntl.h> #include <sys/types.h> #include <stdint.h> #includ…

线性代数行列式

目录 二阶与三阶行列式 二元线性方程组与二阶行列式 三阶行列式 全排列和对换 排列及其逆序数 对换 n阶行列式的定义 行列式的性质 二阶与三阶行列式 二元线性方程组与二阶行列式 若是采用消元法解x1、x2的话则得到以下式子 有二阶行列式的规律可得&#xff1a;分…

canvas之进度条

canvas之进度条 效果&#xff1a; 封装的组件 <template><div class"circle" :style"{ width: props.radius px, height: props.radius px }"><div class"circle-bg" :style"{ width: props.radius - 5 px, height: pr…

再生核希尔伯特空间(RKHS)上的分位回归

1. 基本定义和理论基础 1.1 再生核希尔伯特空间(RKHS) 给定一个非空集合 X \mathcal{X} X&#xff0c;一个希尔伯特空间 H \mathcal{H} H 称为再生核希尔伯特空间&#xff0c;如果存在一个函数 K : X X → R K: \mathcal{X} \times \mathcal{X} \rightarrow \mathbb{R} K…