当前位置: 首页 > news >正文

详细介绍运算符重载函数,清晰明了

祝各位六一快乐~

前言

1.为什么要进行运算符重载?

C++中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C++中重新定义这些运算符赋予已有运算符新的功能,使它能够用于特定类型执行特定的操作

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似

2.什么是运算符重载 ?

运算符重载是通过创建运算符函数实现的,运算符函数定义了重载的运算符将要进行的操作。

1.基本知识

操作符重载,本质上就是函数重载(详细了解可点击阅读函数重载),它大大丰富了已有操作符的含义,方便使用

运算符重载格式如下:

1.函数名:operator+需要重载的运算符符号

2.函数原型:返回值类型 operator+符号(形参参数列表)

3.必须有一个类类型的参数

4.     ::    ?:    .      .*       sizeof  这五个运算符不能重载

5.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义

6.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this

7.不能通过连接其他符号来创建新的操作符:比如operator@

8.运算符重载时必须遵循的原则

  • 重载运算符含义必须清楚;
  • 重载运算符不能有二义性。

9.算符函数重载的两种形式

  • 重载为类的成员函数
  • 重载为类的非成员函数 (非成员函数通常是友元函数)。

注:可以把一个运算符作为一个非成员、非友元函数重载。但是,这样的运算符函数访问类的私有和保护成员时,必须使用类的公有接口中提供的设置数据和读取数据的函数,调用这些函数时会降低性能。可以内联这些函数以提高性能。

补充知识:友元函数

一、友元函数的作用

  • 提供数据共享接口:为不同类之间的成员函数,以及类的成员函数与一般函数之间提供了数据共享的接口。
  • 支持类间紧密协作:当两个或多个类之间需要进行紧密的协作和交互时,友元函数允许直接访问私有成员,减少系统开销,提高效率。
  • 支持运算符重载:在某些情况下,可能需要重载运算符并操作两个不同对象之间的私有数据。此时可以将相应操作符重载函数声明为两个类的友元。

二、友元函数的特点(重点)

  • 与类的成员函数具有一样的权限:友元函数可以访问类的所有成员,包括私有成员。
  • 不属于任何类:友元函数是定义在类外的普通函数,不属于任何类。
  • 没有this指针:由于友元函数不是类的成员函数,因此它没有this指针。

三、友元函数的用法

  • 声明方式:友元函数需要在类中进行声明,前面需要加上friend关键字,可以放在公有部分也可以放在私有部分。
  • 多类友元:一个函数可以是多个类的友元函数,只需要在个各类中分别进行声明。
  • 调用方式:友元函数的调用与一般函数的调用方式和原理一致。

四、注意事项

  • 破坏封装性:友元函数破坏了类的封装性和类数据的隐藏性,因此在使用时需要谨慎考虑。
  • 避免过度使用:原则上应尽量少使用或不使用友元,除非确实能显著提高开发效率。

    2.经典运算符重载的代码示例(主要以日期类为例)

2.1operator+,operator-,operator+=,operator-=

以复数类为例

代码

#include<iostream>
using namespace std;//负数类
class complex
{
public:complex(double r = 0, double i = 0) :_real(r), _imag(i) {}complex operator +(const complex& c); //+运算符complex operator -(const complex& c);//-运算符complex& operator +=(const complex& c); //+=运算符complex& operator -=(const complex& c);//-=运算符complex& operator - ();//求负运算符void Print()const{cout << "(" << _real << "," << _imag << ")" << endl;}
private:double _real;//实部double _imag;//虚部
};
complex complex::operator +(const complex& c) //+运算符
{complex tmp;tmp._real = _real + c._real;tmp._imag = _imag + c._imag;return tmp;
}
complex complex::operator -(const complex& c) //-运算符
{complex tmp;tmp._real = _real - c._real;tmp._imag = _imag - c._imag;return tmp;
}
complex& complex::operator +=(const complex& c) //+=运算符
{_real += c._real;_imag += c._imag;return *this;
}
complex& complex::operator -=(const complex& c) //-=运算符
{_real -= c._real;_imag -= c._imag;return *this;
}
complex& complex::operator - ()//求负运算符
{_real = -_real;_imag = -_imag;return *this;
}
int main()
{complex c1(3.5, 5), c2(6, 8), c3, c4, c5;c3 = c1 + c2;c3.Print();c4 = c2 - c1;c4.Print();c1 += c2;c1.Print();c2.Print();c2 -= c1;c1.Print();c2.Print();c5 = -c2;c5.Print();return 0;
}

2.2前置operator++(--),后置operator++(--)

前置++和后置++的函数名都是operator++(没错,又是函数重载),他们的区别在于前置++没有形参,后置++有一个形参int,但是我们在实际上使用时并不需要给后置++的形参int传实参,int只是为了区分前置++和后置++的标识。

前置--和后置--也是同样用形参int来区分。

以日期类为例

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 0, int month = 0, int day = 0);// 拷贝构造函数// d2(d1)Date(const Date& d);// 获取某年某月的天数int GetMonthDay(int year, int month);// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day)const;// 日期-=天数Date& operator-=(int day);// 日期-天数Date operator-(int day)const;// 前置++Date& operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();void print()const;// 析构函数(日期类无需清理资源,析构函数不必显示写)//void print();//~Date()//{//cout << "~Date()" << endl;//}
private:int _year, _month, _day;
};Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}
int Date::GetMonthDay(int year, int month)
{static int MonthDay[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)){return 29;}else{return MonthDay[month];}
}
void Date::print()const
{cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
Date& Date::operator+=(int day)
{if (day < 0){return *this -= -day;}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month == 13){_month = 1;_year++;}}return *this;
}
Date Date::operator+(int day)const
{Date tmp = *this;tmp += day;return tmp;
}
Date& Date::operator-=(int day)
{if (day < 0){return *this += -day;}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}
Date Date::operator-(int day)const
{Date tmp = *this;tmp -= day;return tmp;
}
void Test1()
{Date d1(2024, 4, 30);Date d2 = d1 + 3;d2.print();Date d3(2024, 12, 31);Date d5 = d3;d3 += 1;d3.print();d5 = d5 - 1;d5.print();d1 -= 30;d1.print();Date d4 = d1 - 3;d4.print();
}
// 前置++
Date& Date::operator++()
{//这里直接用刚刚实现的Date& Date::operator+=(int day)//只是++相当于day=1而已//减少了代码负担*this += 1;return *this;
}
// 后置++
Date Date::operator++(int)
{//这里直接用刚刚实现的Date& Date::operator+(int day)Date tmp = *this;*this += 1;return tmp;
}
// 前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
// 后置--
Date Date::operator--(int)
{Date tmp = *this;*this -= 1;return tmp;
}
void Test2()
{Date d1(2024, 6, 1);Date d2(2023, 12, 31);Date d3 = d1--;Date d4 = d2++;d3.print();d4.print();Date d5 = --d3;Date d6 = ++d4;d5.print();d6.print();
}
int main()
{//Test1();//可以自行测试Test2();
}

2.3operator<,operator<=,operator==,operator!=,operator>=,operator>

只需要实现operator<,operator==,其他的运算符重载就能轻松实现了,下面我们一起看一下吧

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 0, int month = 0, int day = 0);Date(const Date& d);// 获取某年某月的天数int GetMonthDay(int year, int month);// >运算符重载bool operator>(const Date& d);// ==运算符重载bool operator==(const Date& d);// >=运算符重载bool operator >= (const Date& d);// <运算符重载bool operator < (const Date& d);// <=运算符重载bool operator <= (const Date& d);// !=运算符重载bool operator != (const Date& d);void print()const;private:int _year, _month, _day;
};Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}
int Date::GetMonthDay(int year, int month)
{static int MonthDay[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)){return 29;}else{return MonthDay[month];}
}
void Date::print()const
{cout << _year << "年" << _month << "月" << _day << "日" << endl;
}bool Date::operator < (const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year){if (_month < d._month){return true;}else if (_month == d._month){if (_day < d._day){return true;}}}return false;
}
bool Date::operator == (const Date& d)
{return _year == d._year&&_month == d._month&&_day == d._day;
}
bool Date::operator != (const Date& d)
{return !(*this == d);
}
bool Date::operator <= (const Date& d)
{return *this < d || *this == d;
}
bool Date::operator > (const Date& d)
{return !(*this <= d );
}
bool Date::operator >= (const Date& d)
{return !(*this < d);
}
int main()
{Date d1(2024, 3, 2), d2(2023, 5, 6);cout << (d1 == d2) << endl;cout << (d1 != d2) << endl;cout << (d1 <= d2) << endl;cout << (d1 >= d2) << endl;cout << (d1 < d2) << endl;cout << (d1 > d2) << endl;
}

相关文章:

详细介绍运算符重载函数,清晰明了

祝各位六一快乐~ 前言 1.为什么要进行运算符重载&#xff1f; C中预定义的运算符的操作对象只能是基本数据类型。但实际上&#xff0c;对于许多用户自定义类型&#xff08;例如类&#xff09;&#xff0c;也需要类似的运算操作。这时就必须在C中重新定义这些运算符&#xff…...

国内外知名的低代码开发平台下载地址

以下是国内外几款低代码开发平台的列表&#xff0c;包含了下载地址、适应操作系统、是否可以独立部署、优点、缺点以及是否包含流程引擎的信息。 平台名称 下载地址 适应操作系统 是否可以独立部署 优点 缺点 是否包含流程引擎 国内平台 阿里云宜搭 阿里云官网 跨平台…...

【Pr学习】01新建项目起步

【Pr学习】01新建项目起步 1、新建项目2.序列设置2.1新建序列2.2序列参数讲解2.3自定义设置 3.PR窗口认识3.1 项目窗口3.2 源窗口2.4 保存面板 4.剪辑导入4.1 素材导入4.2 视图切换4.3 时间轴4.4轨道工具4.5 节目窗口素材导入 5.基础操作5.1 取消视频音频链接5.2 单独渲染&…...

【Redis延迟队列】redis中的阻塞队列和延迟队列

阻塞队列&#xff08;RBlockingQueue&#xff09; 作用和特点&#xff1a; 实时性&#xff1a;阻塞队列用于实时处理消息。生产者将消息放入队列&#xff0c;消费者可以立即从队列中取出并处理消息。阻塞特性&#xff1a;如果队列为空&#xff0c;消费者在尝试获取消息时会被…...

el-tree常用操作

一、定义 <el-treeclass"myTreeClass":data"dirTreeData":props"dirTreeProps":filter-node-method"filterDirTree":expand-on-click-node"false"node-key"id"node-click"dirTreeNodeClick":allow-…...

SQL 语言:存储过程和触发器

文章目录 基本概述创建触发器更改和删除触发器总结 基本概述 存储过程&#xff0c;类似于高阶语言的函数或者方法&#xff0c;包含SQL语句序列&#xff0c;是可复用的语句&#xff0c;保存在数据库中&#xff0c;在服务器中执行。特点是复用&#xff0c;提高了效率&#xff0c…...

Ubuntu Linux 24.04 使用certbot生成ssl证书

设置域名 1. 将需要生成SSL证书的域名解析到IP地址 idealand.xyz <> 64.176.82.190 检查防火墙的设置 1. 首先查看防火墙的状态&#xff1a; # ufw status 2. 如果防火墙开启了&#xff0c;要开放80和443端口用于certbot验证 # ufw allow 80 # ufw allow 443 生…...

Vivado 比特流编译时间获取以及FPGA电压温度获取(实用)

Vivado 比特流编译时间获取以及FPGA电压温度获取 语言 &#xff1a;Verilg HDL 、VHDL EDA工具&#xff1a;ISE、Vivado Vivado 比特流编译时间获取以及FPGA电压温度获取一、引言二、 获取FPGA 当前程序的编译时间verilog中直接调用下面源语2. FPGA电压温度获取&#xff08;1&a…...

Window下VS2019编译WebRTC通关版

这段时间需要实现这样一个功能&#xff0c;使用WebRTC实现语音通话功能&#xff0c;第一步要做的事情就是编译WebRTC源码&#xff0c;也是很多码友会遇到的问题。 经过我很多天的踩坑终于踩出来一条通往胜利的大路&#xff0c;下面就为大家详细介绍&#xff0c;编译步骤以及踩…...

【云原生 | 60】Docker中通过docker-compose部署kafka集群

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…...

allure测试报告用例数和 pytest执行用例数不相同问题

我出现的奇怪问题&#xff1a; pytest执行了9条用例&#xff0c;但是测试报告确只显示3条用例 我将其中的一个代码删除后&#xff0c;发现allure测试报告又正常了 我觉得很奇怪这个代码只是删除了二维数组的第一列&#xff0c;我检查了半天都找不到问题&#xff0c;只有降低版本…...

Ubuntu 离线安装 gcc、g++、make 等依赖包

前言 项目现场的服务器无法连接互联网&#xff0c;需要提前获取 gcc、g、make 等依赖包。 一、如何获取依赖包 需要准备一台可以连接互联网的电脑&#xff08;如&#xff1a;个人电脑上的虚拟机安装一个与服务器一样的系统&#xff09;&#xff0c;用于下载依赖包。之后把通过…...

Vxe UI vxe-upload 上传组件,显示进度条的方法

vxe-upload 上传组件 查看官网 https://vxeui.com 显示进度条很简单&#xff0c;需要后台支持进度就可以了&#xff0c;后台实现逻辑具体可以百度&#xff0c;这里只介绍前端逻辑。 上传附件 相关参数说明&#xff0c;具体可以看文档&#xff1a; multiple 是否允许多选 li…...

探索API接口:技术深度解析与应用实践

在当今的软件开发和数据交换领域&#xff0c;API&#xff08;应用程序编程接口&#xff09;已经成为了一个不可或缺的工具。它允许不同的软件应用程序或组件之间进行交互和通信&#xff0c;从而实现了数据的共享和功能的扩展。本文将深入探讨API接口的技术原理、设计原则以及在…...

ARM-V9 RME(Realm Management Extension)系统架构之系统安全能力的系统隔离属性

安全之安全(security)博客目录导读 目录 一、系统隔离属性 1、系统配置完整性 1.1、时间隔离 2、关键错误的报告 一、系统隔离属性 1、系统配置完整性 MSD必须确保任何可能危及其安全保证的系统寄存器的正确性和完整性。例如&#xff0c;MSD必须确认内存控制器配置是一致…...

一个班有n个学生,需要把每个学生的简单材料(姓名和学号)输入计算机保存。然后可以通过输入某一学生的姓名查找其有关资料。

当输入一个姓名后&#xff0c;程序就查找该班中有无此学生&#xff0c;如果有&#xff0c;则输出他的姓名和学号&#xff0c;如果查不到&#xff0c;则输出"本班无此人"。 为解此问题&#xff0c;可以分别编写两个函数&#xff0c;函数input_data用来输人n个…...

python的range() 函数

range() 函数 《红楼梦》&#xff0c;又名《石头记》&#xff0c;实际上是一颗神石在人间游历的故事。而这块石头&#xff0c;就是我们的主人公贾宝玉。神石在投胎成宝玉前&#xff0c;向茫茫大士和渺渺真人讲起了自己的故事&#xff1a; 女娲氏炼石补天之时&#xff0c;于大…...

ClickHouse数据管理与同步的关键技术

2024年 5 月 18 日&#xff0c;ClickHouse官方首届杭州 Meetup 活动成功举行。本次活动由 ClickHouse 和阿里云主办&#xff0c;NineData 和云数据库技术社区协办。围绕ClickHouse的核心技术、应用案例、最佳实践、数据管理、以及迁移同步等方面&#xff0c;和行业专家展开交流…...

【一竞技DOTA2】东南亚Bleed战队官宣Emo正式加盟

1、近日东南亚Bleed战队正式发布公告官宣&#xff0c;中国选手Emo以及来自蒙古选手Se加盟战队。 【公告内容如下】 我们很高兴宣布&#xff0c;战队DOTA2名单中添加了两位新成员&#xff0c;请和我们一起欢迎来自中国经验丰富的老将Emo以及来自蒙古的后起之秀Se 一号位&#…...

算法学习笔记(7.3)-贪心算法(最大切分乘问题)

目录 ##问题描述 ##问题思考 ##贪心策略确定 ##代码实现 ##时间复杂度 ##正确性验证 ##问题描述 给定一个正整数 &#x1d45b; &#xff0c;将其切分为至少两个正整数的和&#xff0c;求切分后所有整数的乘积最大是多少 ##问题思考 假设我们将 &#x1d45b; 切分为 &…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...