C++运算符重载全面总结
C++运算符重载全面总结
运算符重载是C++中一项强大的特性,它允许程序员为自定义类型定义运算符的行为。以下是关于C++运算符重载的详细总结:
一、基本概念
1. 什么是运算符重载
运算符重载是指为自定义类型(类或结构体)重新定义或重载已有的运算符,使其能够操作该类型的对象。
2. 运算符重载的限制
- 不能创建新的运算符
- 不能改变运算符的优先级和结合性
- 不能改变运算符的操作数个数
- 部分运算符不能被重载(如
::,.*,.,?:等) - 重载运算符至少有一个操作数是用户定义类型
二、运算符重载的实现方式
1. 成员函数重载
运算符作为类的成员函数重载,隐含this指针作为第一个操作数。
class Complex {
public:Complex operator+(const Complex& other) const {return Complex(real + other.real, imag + other.imag);}
private:double real, imag;
};
2. 友元函数重载
运算符作为非成员函数重载,通常需要声明为友元以访问私有成员。
class Complex {friend Complex operator+(const Complex& a, const Complex& b);
};Complex operator+(const Complex& a, const Complex& b) {return Complex(a.real + b.real, a.imag + b.imag);
}
3. 全局函数重载
对于不访问私有成员的运算符,可以直接定义为全局函数。
Point operator+(const Point& a, const Point& b) {return Point(a.x() + b.x(), a.y() + b.y());
}
三、可重载运算符分类
1. 算术运算符
+, -, *, /, %, +=, -=, *=, /=, %=
class Complex {
public:Complex& operator+=(const Complex& other) {real += other.real;imag += other.imag;return *this;}
};
2. 关系运算符
==, !=, <, >, <=, >=
bool operator==(const Point& a, const Point& b) {return a.x() == b.x() && a.y() == b.y();
}
3. 逻辑运算符
!, &&, ||
class Boolean {
public:bool operator!() const { return !value; }
};
4. 位运算符
&, |, ^, ~, <<, >>, &=, |=, ^=, <<=, >>=
class BitMask {
public:BitMask operator<<(int shift) const {return BitMask(mask << shift);}
};
5. 赋值运算符
=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
class String {
public:String& operator=(const String& other) {// 实现深拷贝return *this;}
};
6. 递增递减运算符
++, --(前缀和后缀)
class Counter {
public:// 前缀++Counter& operator++() {++count;return *this;}// 后缀++Counter operator++(int) {Counter temp = *this;++count;return temp;}
};
7. 下标运算符
[]
class Array {
public:int& operator[](size_t index) {return data[index];}const int& operator[](size_t index) const {return data[index];}
};
8. 函数调用运算符
()
class Functor {
public:int operator()(int x, int y) {return x + y;}
};
9. 成员访问运算符
->, ->*
class SmartPtr {
public:T* operator->() const {return ptr;}
};
10. 类型转换运算符
operator type()
class Rational {
public:operator double() const {return static_cast<double>(numerator) / denominator;}
};
11. 内存管理运算符
new, new[], delete, delete[]
class MemoryPool {
public:void* operator new(size_t size) {return pool.allocate(size);}void operator delete(void* p) {pool.deallocate(p);}
};
四、特殊运算符重载注意事项
1. 输入输出运算符
<<, >> 通常应作为友元函数重载
class Complex {friend ostream& operator<<(ostream& os, const Complex& c);friend istream& operator>>(istream& is, Complex& c);
};ostream& operator<<(ostream& os, const Complex& c) {return os << c.real << "+" << c.imag << "i";
}
2. 赋值运算符
- 应返回
*this的引用以支持链式赋值 - 需要处理自赋值情况
- 通常需要实现拷贝赋值和移动赋值
class String {
public:String& operator=(const String& other) {if (this != &other) {// 实现深拷贝}return *this;}String& operator=(String&& other) noexcept {// 实现移动语义return *this;}
};
3. 类型转换运算符
- 可以声明为
explicit防止隐式转换 - 应谨慎使用以避免意外的类型转换
class SafeBool {
public:explicit operator bool() const { return valid; }
};
五、运算符重载的最佳实践
- 保持直观性:重载的运算符行为应与内置类型相似
- 一致性:相关运算符应一起重载(如
==和!=,<和>等) - 避免过度重载:只为有意义的操作重载运算符
- 考虑对称性:对于二元运算符,考虑是否需要支持交换操作数的顺序
- 性能考虑:尽可能使用引用和移动语义提高效率
- 异常安全:确保运算符重载是异常安全的
六、运算符重载示例
完整示例:复数类
class Complex {
public:Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}// 成员函数重载Complex operator+(const Complex& other) const {return Complex(real + other.real, imag + other.imag);}Complex& operator+=(const Complex& other) {real += other.real;imag += other.imag;return *this;}// 前缀++Complex& operator++() {++real;return *this;}// 后缀++Complex operator++(int) {Complex temp = *this;++real;return temp;}// 友元函数重载friend Complex operator-(const Complex& a, const Complex& b);friend std::ostream& operator<<(std::ostream& os, const Complex& c);// 比较运算符bool operator==(const Complex& other) const {return real == other.real && imag == other.imag;}bool operator!=(const Complex& other) const {return !(*this == other);}private:double real, imag;
};// 非成员函数实现
Complex operator-(const Complex& a, const Complex& b) {return Complex(a.real - b.real, a.imag - b.imag);
}std::ostream& operator<<(std::ostream& os, const Complex& c) {os << c.real << (c.imag >= 0 ? "+" : "") << c.imag << "i";return os;
}
七、C++20新增特性
1. 三路比较运算符 <=>
C++20引入了三路比较运算符,可以简化比较运算符的实现:
class Point {
public:auto operator<=>(const Point&) const = default;// 自动生成 ==, !=, <, <=, >, >=
};
2. 重载co_await
C++20协程支持重载co_await运算符。
总结
运算符重载是C++中实现自定义类型行为一致性的重要手段。合理使用运算符重载可以使代码更直观、更易读。但同时也要注意不要滥用,确保重载的运算符行为符合直觉,并遵循语言惯例。
相关文章:
C++运算符重载全面总结
C运算符重载全面总结 运算符重载是C中一项强大的特性,它允许程序员为自定义类型定义运算符的行为。以下是关于C运算符重载的详细总结: 一、基本概念 1. 什么是运算符重载 运算符重载是指为自定义类型(类或结构体)重新定义或重…...
ArmSoM Sige5 CM5:RK3576 上 Ultralytics YOLOv11 边缘计算新标杆
在计算机视觉技术加速落地的今天,ArmSoM 正式宣布其基于 Rockchip RK3576 的旗舰产品 Sige5 开发板 和 CM5 核心板 全面支持 Ultralytics YOLOv11 模型的 RKNN 部署。这一突破标志着边缘计算领域迎来新一代高性能、低功耗的 AI 解决方案&am…...
【计算机网络】什么是路由?核心概念与实战详解
📌 引言 路由(Routing)是互联网的“导航系统”,负责将数据包从源设备精准送达目标设备。无论是浏览网页、发送消息还是视频通话,背后都依赖路由技术。本文将用通俗类比技术深度的方式,解析路由的核心机制。…...
【ubuntu】linux开机自启动
目录 开机自启动: /etc/rc.loacl system V 使用/etc/rc*.d/系统运行优先级 遇到的问题: 1. Linux 系统启动阶段概述 方法1:/etc/rc5.d/ 脚本延时日志 方法二:使用 udev 规则来触发脚本执行 开机自启动: /etc/…...
dnf install openssl失败的原因和解决办法
网上有很多编译OpenSSL源码(3.x版本)为RPM包的文章,这些文章在安装RPM包时都是执行rpm -ivh openssl-xxx.rpm --nodeps --force 这个命令能在缺少依赖包的情况下能强行执行安装 其实根据Centos的文档,安装RPM包一般是执行yum install或dnf install。后者…...
Java 在人工智能领域的突围:从企业级架构到边缘计算的技术革新
一、Java AI 的底层逻辑:从语言特性到生态重构 在 Python 占据 AI 开发主导地位的当下,Java 正通过技术重构实现突围。作为拥有 30 年企业级开发经验的编程语言,Java 的核心优势在于强类型安全、内存管理能力和分布式系统支持,这…...
操作系统导论——第19章 分页:快速地址转换(TLB)
使用分页作为核心机制来实现虚拟内存,可能会带来较高的性能开销。使用分页,就要将内存地址空间切分成大量固定大小的单元(页),并且需要记录这些单元的地址映射信息。因为这些映射信息一般存储在物理内存中,…...
计算机网络:流量控制与可靠传输机制
目录 基本概念 流量控制:别噎着啦! 可靠传输:快递必达服务 传输差错:现实中的意外 滑动窗口 基本概念 换句话说:批量发货排队验收 停止-等待协议 SW(发1份等1份) 超时重传:…...
SaaS、Paas、IaaS、MaaS、BaaS五大云计算服务模式
科普版:通俗理解五大云计算服务模式 1. SaaS(软件即服务) 一句话解释:像“租用公寓”,直接使用现成的软件,无需操心维护。 案例:使用钉钉办公、在网页版WPS编辑文档。服务提供商负责软件更新和…...
计算机网络 - 三次握手相关问题
通过一些问题来讨论 TCP 协议中的三次握手机制 说一下三次握手的大致过程?为什么需要三次握手?2 次不可以吗?第三次握手,可以携带数据吗?第二次呢?三次握手连接阶段,最后一次ACK包丢失…...
通过使用 include 语句加载并执行一个CMake脚本来引入第三方库
通过使用 include 语句加载并执行一个CMake脚本来引入第三方库 当项目中使用到第三方库时,可以通过使用 include 语句来加载并执行一个CMake脚本,在引入的CMake脚本中进行第三方库的下载、构建和库查找路径的设置等操作,以这种方式简化项目中…...
架构生命周期(高软57)
系列文章目录 架构生命周期 文章目录 系列文章目录前言一、软件架构是什么?二、软件架构的内容三、软件设计阶段四、构件总结 前言 本节讲明架构设计的架构生命周期概念。 一、软件架构是什么? 二、软件架构的内容 三、软件设计阶段 四、构件 总结 就…...
JMeter使用
1.简介 1.1 打开方式 ①点击bat,打开 ②添加JMeter系统环境变量,输⼊命令jmeter即可启动JMeter⼯具 1.2 配置 简体中文 放大字体 1.3 使用 ①添加线程组 ②创建http请求 2. 组件 2.1 线程组 控制JMeter将⽤于执⾏测试的线程数,也可以把⼀个线程理解为⼀个测…...
Ant Design Vue 表格复杂数据合并单元格
Ant Design Vue 表格复杂数据合并单元格 官方合并效果 官方示例 表头只支持列合并,使用 column 里的 colSpan 进行设置。 表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。 <temp…...
Fiddler为什么可以看到一次HTTP请求数据?
1、作为代理服务器 Fiddler作为代理服务器,拦截了设备与互联网服务器之间的所有HTTP和HTTPS流量。当客户端(如浏览器)发送请求时,请求先到达Fiddler,然后由Fiddler转发到目标服务器;服务器的响应也会返回给…...
第十九讲 | XGBoost 与集成学习:精准高效的地学建模新范式
🟨 一、为什么要学习集成学习? 集成学习(Ensemble Learning) 是一种将多个弱学习器(如决策树)组合成一个强学习器的策略。它在地理学、生态学、遥感分类等领域表现尤为突出。 📌 应用优势&#…...
基于 GoFrame 框架的电子邮件发送实践:优势、特色与经验分享
1. 引言 如果你是一位有1-2年Go开发经验的后端开发者,可能已经熟悉了Go语言在性能和并发上的天然优势,也曾在项目中遇到过邮件发送的需求——无论是用户注册时的激活邮件、系统异常时的通知,还是营销活动中的批量促销邮件,邮件功…...
ECharts 如何实现柱状图悬停时,整个背景区域均可触发点击事件
1. 前言 ECharts 柱状图的点击事件默认仅响应柱子本身的点击,本文旨在实现整个背景区域均可触发点击事件 2. 实现思路 核心:全局监听 坐标判断 数据转换 通过 getZr() 监听整个画布点击,结合像素坐标判断是否在图表区域内通过 containPi…...
金融简单介绍及金融诈骗防范
在当今社会,金融学如同一股无形却强大的力量,深刻影响着我们生活的方方面面。无论是个人的日常收支、投资理财,还是国家的宏观经济调控,都与金融学紧密相连。 一、金融学的概念 金融学,简单来说,是研…...
cursor+高德MCP:制作一份旅游攻略
高德开放平台 | 高德地图API (amap.com) 1.注册成为开发者 2.进入控制台选择应用管理----->我的应用 3.新建应用 4.点击添加Key 5.在高德开发平台找到MCP的文档 6.按照快速接入的步骤,进行操作 一定要按照最新版的cursor, 如果之前已经安装旧的版本卸载掉重新安…...
软件版本命名规范Semantic Versioning
语义化版本控制(Semantic Versioning,简称 SemVer)是一种广泛采用的版本号管理规范,旨在通过版本号传达软件更新的性质和影响,帮助开发者和用户理解每次发布的变更内容 🔢 版本号结构 语义化版本号通常采…...
Uniapp: 大纲
目录 一、基础巩固1.1、Uniapp:下拉选择框ba-tree-picker1.2、Uniapp:确认框1.3、Uniapp:消息提示1.4、Uniapp:获取当前定位坐标 二、项目配置2.1、Uniapp:修改端口号2.2、Uniapp:本地存储 一、基础巩固 1.1、Uniapp:…...
Kubernetes控制平面组件:API Server Webhook 授权机制 详解
云原生学习路线导航页(持续更新中) kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计(一)Kubernetes架构原则和对象设计(二)Kubernetes架构原则和对象设计(三)Kubernetes控…...
【KWDB 创作者计划】_产品技术解读_1
【KWDB 创作者计划】_产品技术解读_1 一、存储引擎:高性能混合存储架构1. 存储模型设计2. 存储压缩与编码3. 持久化策略二、KWDB 组件源码解析1. 核心模块分层架构2. 关键组件源码剖析三、KWDB 特性代码通读1. 实时分析能力(Real-Time OLAP)2. 混合负载隔离(HTAP)3. 智能索…...
Python Cookbook-6.2 定义常量
任务 你需要定义一些模块级别的变量(比如命名的常量),而且客户代码无法将其重新绑定。 解决方案 你可以把任何对象当做模块一样安装。将下列代码存为一个模块const.py,并放入你的Python的sys.path 指定的目录中: class _const(object):class ConstEr…...
【Python爬虫】简单案例介绍2
本文继续接着我的上一篇博客【Python爬虫】简单案例介绍1-CSDN博客 目录 跨页 3.2 环境准备 跨页 当对单个页面的结构有了清晰的认识并成功提取数据后,接下来就需要考虑页面之间的跨页问题。此时我们便迎来了下一个关键任务:如何实现跨页爬取…...
【神经网络】python实现神经网络(四)——误差反向传播的基础理论
一.反向传播 本章将介绍能够高效计算权重参数的梯度的方法——误差反向传播法,这里简单介绍一下什么是反向传播,加入有个函数y = f(x),那么它的反向传播为图下这个样子: 反向传播的计算顺序是,将输入信号E乘以节点的局部导数,然后将结果传递给下一个节点。这里所…...
【SQL】COUNT... FILTER 的适用场景
【SQL】COUNT... FILTER 的适用场景 一、引言二、FILTER 基础学习2.1 语法解析2.2 适用范围2.2.1 主流数据库支持情况 2.3 技术优势2.3.1 性能优化2.3.2 等阶写法对比 2.4 适用场景2.4.1 多维统计报表2.4.2 动态数据过滤2.4.3 复杂条件处理 三、总结 一、引言 今天参加业务评审…...
I/O进程(全)
I/O 一、标准IO 1.概念 在C库中定义的一组用于输入输出的函数 2.特点 (1).通过缓冲机制减少系统调用,提高效率 (2.)围绕流进行操作,流用FILE *来描述(3).标准IO默认打开了三个流,stdin(标准输入)、stdout(标…...
vue2使用ezuikit-js播放萤石视频
需求:需要在大屏上播放萤石视频,用到官方的ezuikit-js插件实现,并实现视频播放切换功能。有个问题至今没有解决,就是萤石视频的宽高是固定的,不会根据大屏缩放进行自适应。我这边做了简单的刷新自适应。 1.下载ezuikit…...
