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/8/2 19:16:49阅读更多 →
UE4SS深度指南:从脚本注入到模组生态构建的完整实践

UE4SS深度指南:从脚本注入到模组生态构建的完整实践

1. 项目概述:UE4SS是什么,以及为什么你需要它如果你是一个深度使用虚幻引擎4(UE4)进行游戏开发或模组制作的开发者,那么“UE4SS”这个名字对你来说应该不陌生。简单来说,UE4SS是一个功能强大的脚本系统&…

2026/8/2 19:14:49阅读更多 →
基于ESP32与电子墨水屏的TRMNL智能终端DIY全攻略

基于ESP32与电子墨水屏的TRMNL智能终端DIY全攻略

1. 项目初探:TRMNL 7.5" (OG) 套件是什么? 如果你对Arduino和ESP32已经有些了解,并且正在寻找一个能让你“玩”起来,同时又能做出一个兼具实用性和酷炫外观的项目,那么TRMNL 7.5" (OG) DIY套件很可能就是你的…

2026/8/2 19:14:49阅读更多 →
从静态到动态:用Singularity-LTX-2.3_OmniCine_V1让AI视频生成变得简单

从静态到动态:用Singularity-LTX-2.3_OmniCine_V1让AI视频生成变得简单

从静态到动态:用Singularity-LTX-2.3_OmniCine_V1让AI视频生成变得简单 【免费下载链接】Singularity-LTX-2.3_OmniCine_V1 项目地址: https://ai.gitcode.com/hf_mirrors/WarmBloodAban/Singularity-LTX-2.3_OmniCine_V1 你是否曾经梦想过将静态图像变成生…

2026/8/2 20:23:14阅读更多 →
Czkawka视频查重工具:三步快速清理重复视频的完整指南

Czkawka视频查重工具:三步快速清理重复视频的完整指南

Czkawka视频查重工具:三步快速清理重复视频的完整指南 【免费下载链接】czkawka Multi functional app to find duplicates, empty folders, similar images etc. 项目地址: https://gitcode.com/GitHub_Trending/cz/czkawka 还在为硬盘中堆积如山的重复视频…

2026/8/2 20:23:14阅读更多 →
RK3399 Linux USB HID Gadget配置实战:从内核到自定义报告描述符

RK3399 Linux USB HID Gadget配置实战:从内核到自定义报告描述符

1. 项目概述:为什么要在RK3399上折腾HID Gadget?最近在做一个嵌入式项目,需要把一块RK3399开发板变成一个USB键盘或者鼠标,直接通过USB线连接到电脑上就能输入。听起来是不是有点像那些“硬件按键精灵”或者自定义控制面板&#x…

2026/8/2 20:23:14阅读更多 →
macos支持的视频封面制作软件?5款Mac剪辑横评实测

macos支持的视频封面制作软件?5款Mac剪辑横评实测

Mac 上到底有没有顺手又能量产的封面制作工具?做短视频矩阵和口播账号的人,几乎都被「封面」卡过:单条精修还能靠 PS 或在线模板磨一磨,一旦日更、矩阵、多平台分发,封面就开始拖后腿——风格不统一、尺寸要反复改、人…

2026/8/2 20:23:14阅读更多 →
LeetDown深度解析:A6/A7芯片iOS设备降级技术与实践

LeetDown深度解析:A6/A7芯片iOS设备降级技术与实践

LeetDown深度解析:A6/A7芯片iOS设备降级技术与实践 【免费下载链接】LeetDown a macOS app that downgrades A6 and A7 iDevices to OTA signed firmwares 项目地址: https://gitcode.com/gh_mirrors/le/LeetDown 对于拥有iPhone 5、iPhone 5s、iPad 4等老旧…

2026/8/2 20:23:14阅读更多 →
如何通过ActivityWatch实现智能时间管理:免费开源工具的完整指南

如何通过ActivityWatch实现智能时间管理:免费开源工具的完整指南

如何通过ActivityWatch实现智能时间管理:免费开源工具的完整指南 【免费下载链接】activitywatch The best free and open-source automated time tracker. Cross-platform, extensible, privacy-focused. 项目地址: https://gitcode.com/gh_mirrors/ac/activityw…

2026/8/2 20:21:14阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:10阅读更多 →
限时公开!某头部SaaS公司内部AI模板工厂架构文档(含5类行业模板源码+性能压测报告)

限时公开!某头部SaaS公司内部AI模板工厂架构文档(含5类行业模板源码+性能压测报告)

更多请点击: https://intelliparadigm.com 第一章:AI模板批量生成的核心价值与落地全景 AI模板批量生成正从实验性工具演进为现代软件工程的关键基础设施。它通过语义理解、上下文感知与结构化约束,将重复性高、模式明确的代码/文档/配置生成…

2026/8/2 0:00:12阅读更多 →
如何快速找回消失的网页:Web Archives浏览器扩展终极指南

如何快速找回消失的网页:Web Archives浏览器扩展终极指南

如何快速找回消失的网页:Web Archives浏览器扩展终极指南 【免费下载链接】web-archives Browser extension for viewing archived and cached versions of web pages, available for Chrome, Edge and Safari 项目地址: https://gitcode.com/gh_mirrors/we/web-a…

2026/8/2 0:00:13阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:10阅读更多 →
限时公开!某头部SaaS公司内部AI模板工厂架构文档(含5类行业模板源码+性能压测报告)

限时公开!某头部SaaS公司内部AI模板工厂架构文档(含5类行业模板源码+性能压测报告)

更多请点击: https://intelliparadigm.com 第一章:AI模板批量生成的核心价值与落地全景 AI模板批量生成正从实验性工具演进为现代软件工程的关键基础设施。它通过语义理解、上下文感知与结构化约束,将重复性高、模式明确的代码/文档/配置生成…

2026/8/2 0:00:12阅读更多 →
如何快速找回消失的网页:Web Archives浏览器扩展终极指南

如何快速找回消失的网页:Web Archives浏览器扩展终极指南

如何快速找回消失的网页:Web Archives浏览器扩展终极指南 【免费下载链接】web-archives Browser extension for viewing archived and cached versions of web pages, available for Chrome, Edge and Safari 项目地址: https://gitcode.com/gh_mirrors/we/web-a…

2026/8/2 0:00:13阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/2 1:29:34阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/2 2:32:55阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/2 2:09:20阅读更多 →