c++--运算符重载
1.重载的运算符(1).重载运算符函数的参数数量与该运算符作用的运算对象数量一样多。(2).除了重载的函数调用运算符operator()之外其他重载运算符不能含有默认实参。(3).对一个重载的运算符其优先级和结合律与对应的内置运算符保持一致。(4).当一个重载的运算符是成员函数时this绑定到左侧运算对象。故成员运算符函数的参数数量比运算对象数量少一个。(5).对一个运算符函数或者是类的成员或者至少含一个类类型的参数。2.运算符函数的调用形式// 假设有非成员函数operator显式operator(data1, data2);隐式data1data2// 假设有成员函数operator显式data1.operator(data2)隐式data1data23.关于将运算符函数定义为成员还是非成员赋值下标[]调用成员访问箭头-必须为成员。4.运算符重载4.1.重载(1).通常输出运算符的第一个形参是一个非常量ostream对象的引用。a. 为引用是因为ostream对象不能被拷贝。b. 非常量是因为向流写入内容会改变其状态。(2).第二个形参一般是一个常量的引用该常量是我们想打印的类类型。a. 是引用是因为可以避免值拷贝。b. 常量是因为打印对象不会改变对象的内容。(3). 为与其他输出运算符一致operator一般返回它的ostream形参。(4). 一个实例#include iostream class A { public: int m_a; int m_b; }; std::ostream operator(std::ostream os, const Aitem) { os item.m_a item.m_b; return os; }4.2.重载(1). 通常输入运算符的第一个形参是运算符将要读取的流的引用(2). 第二个形参是将要读入到的非常量对象的引用。(3). 该运算符通常会返回某个给定流的引用。(4). 一个实例#include iostream class A { public: int m_a; int m_b; }; std::istream operator(std::istream is, A item) { char a; is item.m_a a item.m_b; return is; }执行输入时可能发生下列错误(1). 流含有错误类型的数据时读取操作可能失败。(2). 读取操作到达文件末尾或遇到输入流的其它错误时也会失败。4.3.算术运算符4.3.1.最佳实践(1). 类定义了一个算术运算符时一般也要定义一个复合赋值运算符。(2). 一般借用复合赋值运算符来定义算术运算符。(3). 通常算术和关系运算符定义为非成员函数以允许左侧或右侧的运算对象进行转换。(4). 这些运算符一般不需改变运算对象的状态故形参可以是常量的引用。(5). 算术运算的结果一般位于局部变量内。操作完成一般返回局部变量的副本作为结果。(6). 复合赋值运算符更适合作为类成员来定义。复合赋值应该返回引用类型以便支持链式赋值(7). 一个实例#include iostream class A { friend bool operator(const A a1, const A a2); public: A():m_a(0), m_b(0){} A(int i):m_a(i), m_b(i){} void print() { printf(a_%d,b_%d\n, m_a, m_b); } A operator(const A a2) { m_a m_a a2.m_a; m_b m_b a2.m_b; return *this; } private: int m_a; int m_b; }; A operator(const A a1, const A a2) { A sum a1; sum a2; return sum; } bool operator(const A a1, const A a2) { return a1.m_a a2.m_a a1.m_b a2.m_b; } bool operator!(const A lhs, const A rhs) { return !(lhs rhs); } int main() { A a1(10); A a2(10); A a3 a1 a2; a3.print(); return 0; }上述是一个为类型A定义运算符!的实例。我们采用类成员定义复合赋值。下述是一个复合赋值采用非成员的版本。#include iostream class A { friend bool operator(const A a1, const A a2); friend A operator(A a1, const A a2); public: A():m_a(0), m_b(0){} A(int i):m_a(i), m_b(i){} void print() { printf(a_%d,b_%d\n, m_a, m_b); } private: int m_a; int m_b; }; // 返回值是复合赋值作为表达式的结果 // 参数1是复合赋值左边操作数此操作数会被复合赋值所影响。 A operator(A a1, const A a2) { a1.m_a a2.m_a; a1.m_b a2.m_b; return a1; } A operator(const A a1, const A a2) { A sum a1; sum a2; return sum; } bool operator(const A a1, const A a2) { return a1.m_a a2.m_a a1.m_b a2.m_b; } bool operator!(const A lhs, const A rhs) { return !(lhs rhs); } int main() { A a1(10); A a2(10); A a3 a1 a2; a3.print(); return 0; }4.4.关系运算符4.4.1.最佳实践(1). 通常关系运算符定义为非成员函数以允许左侧或右侧的运算对象进行转换。(2). 这些运算符一般不需改变运算对象的状态故形参可以是常量的引用。以下是一个关系运算符重载的例子#include iostream class A { friend bool operator(const A a1, const A a2); public: A():m_a(0),m_b(0){} A(int i):m_a(i),m_b(i){} private: int m_a; int m_b; }; bool operator(const A a1, const A a2) { if(a1.m_a a2.m_a a1.m_b a2.m_b) { return true; } else { return false; } } bool operator!(const A a1, const A a2) { return !(a1 a2); } int main() { A a1(1), a2(2); printf(a1a2?%d\n, a1 a2); return 0; }4.5.赋值运算符(1). 赋值运算符限制性因素有赋值作为表达式存在一个结果数值。赋值会修改左边操作数状态。(2). 最佳实践a. 赋值一般实现为成员函数b. 为类型自定义赋值运算符时运算符内部必须处理b.1. 基类部分赋值b.2. 类型成员赋值c. 为类型自定义赋值运算符时需要考虑自赋值场景。d. 赋值与拷贝针对包含资源的类涉及浅拷贝深拷贝的概念。又涉及到左值右值移动语义完美转发的概念。这些后续统一放在专门一篇讲解。(3). 一个实例#include iostream class Norm1 { public: Norm1(char i):m_i(i){} void print() { printf(norm1:%c\n, m_i); } private: char m_i; }; class Norm2 { public: Norm2(char i):m_i(i){} void print() { printf(norm2:%c\n, m_i); } private: char m_i; }; class Base { public: Base(char c b):m_n1(c),m_n2(c){} void print() { printf(base:\n); m_n1.print(); m_n2.print(); } private: Norm1 m_n1; Norm2 m_n2; }; class A : public Base { public: A(char c a):Base(c), m_n1(c1),m_n2(c1){} A operator(const A a) { if(this a) { return *this; } Base::operator(a); m_n1 a.m_n1; m_n2 a.m_n2; return *this; } void print() { Base::print(); m_n1.print(); m_n2.print(); } private: Norm1 m_n1; Norm2 m_n2; }; int main() { A a1(x); A a2(a); a1.print(); a2.print(); a1 a2; printf(after:\n); a1.print(); a2.print(); return 0; }4.6.下标运算符对下标运算符最好定义常量和非常量版本对常量版本返回常量引用。4.6.1. 强制性约束从强制性约束角度要求形参列表只能有一个形参#include iostream class Norm { public: void print() const { printf(Norm_%d\n, m_i); } private: int m_i; }; class A { public: int operator[](Norm n) { printf(test[]\n); return 1; } private: Norm m_arrA[10]; }; int main() { A a; Norm n; int i a[n]; return 0; }上述是一个合法的重载的[]运算符。4.6.2. 最佳实践(1). 形参最好是std::size_t。(2). 重载运算符最好提供常量版本非常量版本。这样对类型的常量实例非常量实例均可执行[]运算。(3). 返回值应该设计成引用类型。标准库类型[]运算符也均返回引用类型。#include iostream class Norm { public: void print() const { printf(Norm_%d\n, m_i); } private: int m_i; }; class A { public: Norm operator[](std::size_t i) { printf([]\n); return m_arrA[i]; } const Norm operator[](std::size_t i) const { printf([]const\n); return m_arrA[i]; } private: Norm m_arrA[10]; }; int main() { A a; a[1].print(); const A a1 A(); a1[1].print(); return 0; }上述是一个[]运算符重载的最佳实例4.7.递增和递减运算符4.7.1.强制性约束(1).对后置版本的--形参列表必须提供单个类型为int的形参。(2).对前置版本的--形参列表必须为空。#include iostream class A { public: A() : m_i(0) {} int operator() { printf(()\n); m_i; return 1; } int operator(int n) { printf((int)\n); A temp *this; m_i; return 1; } private: int m_i; }; int main() { A a; a; a; return 0; }上述是一个合法的前置后置运算符的重载实现。4.7.2.最佳实践(1). 定义--运算符时候应该同时定义前置版本后置版本。(2). 前置版本应该返回类型自身的引用。后置版本应该返回类型自身。与标准库类型保持一致。(3). 不应该提供常量版本。#include iostream class Norm { private: int m_i; }; class A { public: A() : m_i(0) {} A operator() { printf(()\n); m_i; return *this; } A operator(int) { printf((int)\n); A temp *this; m_i; return temp; } private: int m_i; }; int main() { A a; a; a; return 0; }上述是一个前置后置的最佳实践。4.8.成员访问运算符*-4.8.1. 强制性约束(1).对*运算符必须提供0个形参或1个形参。(2).对-运算符必须提供0个形参。#include iostream class Norm { public: Norm(int i) : m_i(i) {} void print() { printf(i_%d\n, m_i); } private: int m_i; }; class A { public: int operator*(Norm) { printf(*\n); return 1; } int operator-() { printf(-\n); return 2; } private: int m_i; }; int main() { A a; A *p a; Norm n(1); p-operator-(); p-operator*(n); a.operator*(n); a.operator-(); // a-print(); //*a; return 0; }上述我们为类型定义了一个合法的*运算符一个合法的-运算符。4.8.2.最佳实践(1).*运算符的形参应该是0个。因为只有这样才能使用A a; *a;这样的方式触发*运算符访问。(2).-运算符的返回类型应该要么是重载了-运算符的类型要么是指针类型。因为如下述我们执行A a; a-print();这样的操作时。操作处理细节为a. 若a重载了-运算符。则执行运算符获得返回值。否则报错。b. 若返回值是指针类型进入到对指针类型执行-情形。终止。c. 若返回值不是指针类型且重载了-运算符则执行运算符获得返回值。否则报错终止。b. 进入2。我们下述的a-print()对应的输出为#include iostream class Norm { public: Norm(int i) : m_i(i) {} Norm *operator-() { printf(norm -\n); return this; } void print() { printf(i_%d\n, m_i); } private: int m_i; }; class A { public: Norm operator*() { Norm n(1); printf(*\n); return n; } Norm operator-() { Norm n(11); printf(-\n); return n; } private: int m_i; }; int main() { A a; A *p a; p-operator-(); p-operator*(); a.operator*(); a.operator-(); a-print(); *a; return 0; }4.8.3. 注意点以4.8.2中实例为说明对象。整理c类型中成员访问细节。int main() { A a; A *p a; p-operator-(); p-operator*(); a.operator*(); a.operator-(); a-print(); *a; return 0; }(1). 针对指针类型基于指针执行-可以访问到指针指向对象的成员。此行为不允许重载。(2). 针对非指针类型称其为对象类型基于对象类型执行.可以访问到对象的成员。此行为不允许重载。(3). 调用类型*-运算符的形式有显式和隐式。a. 显式调用诸如int main() { A a; A *p a; p-operator-(); p-operator*(); a.operator*(); a.operator-(); return 0; }b.隐式调用诸如int main() { A a; a-print(); *a; return 0; }4.9.函数调用运算符4.9.1.强制性约束对形参列表无强制性约束。#include iostream class A { public: A() {} int operator()(int) { printf((int)\n); return 0; } int operator()(int, int) { printf((int,int)\n); return 1; } private: int m_i; }; int main() { A a; a(1); a(1, 2); return 0; }上述我们定义了两个函数调用运算符分别接收一个参数两个参数。定义类函数调用运算符的类类的对象称作函数对象。4.10.转换构造函数4.10.1.强制性约束我们称只传递一个实参即可调用的构造函数为转换构造函数#include iostream class A { public: A(int i, int j 0) : m_i(i) { printf(A(int)_%d\n, i); } private: int m_i; }; void fun(A a) { } int main() { fun(1); return 0; }上述我们定义了一个转换构造函数。因为有了此转换构造函数上述fun(1)执行中先基于1构造得到类型A的实例再执行函数调用。若要阻止这类默认转换只需将转换构造用explicit修饰。此时只能通过显式构造基于int得到类型A实例。#include iostream class A { public: explicit A(int i, int j 0) : m_i(i) { printf(A(int)_%d\n, i); } private: int m_i; }; void fun(A a) { } int main() { fun(A(1)); return 0; }4.11.类型转换运算符4.11.1.强制性约束类型转换运算符的形参列表必须为空#include iostream class Norm { public: private: char m_c; }; class A { public: explicit A(int i, int j 0) : m_i(i) { printf(A(int)_%d\n, i); } operator int() { printf(int()\n); return m_i; } operator Norm() { printf(Norm()\n); Norm n; return n; } private: int m_i; }; void fun(A a) { } int main() { fun(A(1)); A a(1); int n 1 a; printf(n_%d\n, n); Norm nn a; return 0; }上述我们定义了两个类型转换运算符分别转换到intNorm类型。

相关新闻

如何用GHelper实现华硕笔记本的终极硬件控制:轻量级开源方案深度解析

如何用GHelper实现华硕笔记本的终极硬件控制:轻量级开源方案深度解析

如何用GHelper实现华硕笔记本的终极硬件控制:轻量级开源方案深度解析 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivoboo…

2026/10/8 17:51:21 阅读更多 →
Ubuntu 上搭建Samba和nfs服务

Ubuntu 上搭建Samba和nfs服务

一、Ubuntu上搭建Samba服务1.安装Sambasudo apt-get install samba samba-common2.如果你开启了防火墙,关闭sudo systemctl stop ufw3.配置Samba,编辑配置文件sudo vim /etc/samba/smb.conf直接共享家目录,修改如下:4.添加一个用户…

2026/10/9 17:08:07 阅读更多 →
从零构建Godot游戏控制台:打造高效运行时调试工具

从零构建Godot游戏控制台:打造高效运行时调试工具

1. 项目概述:为什么要在Godot里造一个控制台? 如果你用过Unity或者Unreal,可能对编辑器里的Console窗口不陌生,那里是日志、警告和错误的聚集地,也是调试时最常打交道的界面之一。但当你切换到Godot,尤其是…

2026/10/8 19:49:28 阅读更多 →

最新新闻

Java基础探秘:JSON解析与反射机制如何协同工作

Java基础探秘:JSON解析与反射机制如何协同工作

最近在写一个接口的时候,我盯着IDE里那几十行setter调用,脑子里突然冒出一个问题:前端传过来一段JSON字符串,我一行代码就把它变成了业务对象,中间到底是谁在帮我完成键名和字段的匹配?顺着这个疑问查下去&…

2026/10/14 6:41:29 阅读更多 →
QGIS 加载天地图出现灰色影像:层级参数 l 与 z 的坑,附四种返回码对照

QGIS 加载天地图出现灰色影像:层级参数 l 与 z 的坑,附四种返回码对照

场景QGIS 里挂天地图底图,图层加成功了,瓦片也在刷,画面却是一片灰,每个格子上写着"此级别下,该区域无影像"。打开浏览器 F12 一看,状态码 200,图片也确实回来了。这时候大多数人会往…

2026/10/14 6:41:29 阅读更多 →
Agent通信协议选型指南:JSON-RPC、MCP、A2A与ACP的分层实践

Agent通信协议选型指南:JSON-RPC、MCP、A2A与ACP的分层实践

1. 为什么 Agent 通信协议突然“百花齐放”过去一年里,只要你在做 AI Agent 相关的开发,几乎绕不开一个困惑:同样是让两个智能体互相说话,怎么一会儿是 JSON-RPC,一会儿是 MCP,转头又冒出 A2A、ACP&#xf…

2026/10/14 6:41:29 阅读更多 →
Chat2DB 实战:AI 生成 SQL 的数据库管理工具与避坑指南

Chat2DB 实战:AI 生成 SQL 的数据库管理工具与避坑指南

简介:Chat2DB项目代码包是一份集成人工智能能力的开源数据库管理工具示例,面向需要降低数据库操作门槛的开发者、数据分析师以及对自然语言生成SQL感兴趣的技术人员。整个资源共包含3个文件,涵盖inscode入口文件、html介绍文档以及gitignore配…

2026/10/14 6:41:29 阅读更多 →
PS5串流实战:AnyPS5配置与网络调优全攻略

PS5串流实战:AnyPS5配置与网络调优全攻略

把一台PS5玩出三台机器的效果,是不少玩家都在琢磨的事。AnyPS5这个项目,说白了就是干这件事:让PS5不再被客厅电视绑住,而是把画面和操作实时串流到你手边的任何一块屏幕上——笔记本、平板、手机、甚至办公电脑。我在这个方向上前…

2026/10/14 6:41:29 阅读更多 →
C#调用WebService获取PDF转图片:选型与踩坑实战

C#调用WebService获取PDF转图片:选型与踩坑实战

做C#开发这几年,遇到“调用WebService获取PDF文件再转换为图片”这种需求不算少。可能是一个审批系统需要预览合同,也可能是一个报表平台需要把服务端生成的文件转成缩略图展示。总之核心工作就两件事:把远程文件拿下来,再在本地转…

2026/10/14 6:40:29 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →