C++ 运算符重载

目录

前言 

算术运算符重载

加号运算符

位运算符重载

左移运算符

自增自减运算符重载

前置++自增运算符

后置++自增运算符

赋值运算符重载

等号赋值运算符重

关系运算符重载

相等 

不等 

函数调用运算符重载

总结


前言 

在C++中,运算符重载是一种强大的特性,允许您重新定义已定义的运算符,以便它们适用于用户自定义类型。通过运算符重载,您可以编写自定义类型的运算符行为,使得用户自定义类型的对象可以像内置类型一样进行运算。

算术运算符重载

  • +:执行加法操作,通常用于数字或字符串的拼接。
  • -:执行减法操作,通常用于数字之间的减法运算。
  • *:执行乘法操作,通常用于数字之间的乘法运算。
  • /:执行除法操作,通常用于数字之间的除法运算。

通过重载这些算术运算符,您可以定义自定义类型对象之间的加减乘除操作。这使得用户自定义类型的对象可以像内置类型一样进行算术运算。

加号运算符

#include <iostream>
using namespace std;class Person {
public:Person() {};Person(int a, int b){this->m_A = a;this->m_B = b;}// 成员函数实现 + 号运算符重载Person operator+(const Person& p) {Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}public:int m_A;int m_B;
};// 全局函数实现 + 号运算符重载
//Person operator+(const Person& p1, const Person& p2) {
//	Person temp(0, 0);
//	temp.m_A = p1.m_A + p2.m_A;
//	temp.m_B = p1.m_B + p2.m_B;
//	return temp;
//}// 运算符重载 可以发生函数重载,就是可以根据参数的不同去分别调用不同的operator运算符重载函数
Person operator+(const Person& p2, int val)
{Person temp;temp.m_A = p2.m_A + val;temp.m_B = p2.m_B + val;return temp;
}void test() {Person p1(10, 10);Person p2(20, 20);// 成员函数方式Person p3 = p2 + p1;  // 相当于 p2.operaor+(p1)cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl; // 30 30Person p4 = p3 + 10; // 相当于 operator+(p3,10)cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl; // 40 40}int main() {test();return 0;
}

位运算符重载

  • &:按位与运算符,对两个操作数逐位进行与运算。
  • |:按位或运算符,对两个操作数逐位进行或运算。
  • ^:按位异或运算符,对两个操作数逐位进行异或运算。
  • ~:按位取反运算符,对操作数逐位取反。
  • <<:左移运算符,将操作数的二进制位向左移动指定的位数。
  • >>:右移运算符,将操作数的二进制位向右移动指定的位数。

通过重载位运算符,您可以定义自定义类型对象之间的按位操作。这使得自定义类型的对象可以进行位级运算。

左移运算符

#include <iostream>
using namespace std;
#include <string>/* 作用:可以输出自定义数据类型 */class Person {friend ostream& operator<<(ostream& out, Person& p); // 全局函数做Person类的友元,可以访问类的私有成员public:Person(int a, int b){this->m_A = a;this->m_B = b;}//成员函数 实现不了  p << cout 不是我们想要的效果//void operator<<(Person& p){//}private:int m_A;int m_B;
};//全局函数实现左移重载
//ostream对象只能有一个,故使用 &引用接收,不会创建新对象
ostream& operator<<(ostream& out, Person& p) { out << "a:" << p.m_A << " b:" << p.m_B;return out; // 需返回cout引用,达到链式调用的效果
}void test() {Person p1(10, 20);cout << p1 << "hello world" << endl; // a:10 b:20hello world  链式编程  
}int main() {test(); // 重载左移运算符配合友元可以实现输出自定义数据类型return 0;
}

自增自减运算符重载

通过重载自增和自减运算符,您可以定义自定义类型对象的自增和自减操作。这允许您使用++--来递增或递减对象的值。

前置++自增运算符

前置++,必须返回引用,不能返回值,因为要对同一原对象操作

        解释一下 test01函数中的 cout << ++myInt << endl。首先,递增运算符的重载函数++myInt会被执行,将myInt的值加1,并返回递增后的对象引用。然后,左移运算符的重载函数operator<<会接受递增后的对象作为参数,并将其输出到标准输出流cout中。

#include <iostream>
using namespace std;
#include <string>class MyInteger {friend ostream& operator<<(ostream& out, MyInteger myint);public:MyInteger() {m_Num = 0;}//前置++,必须返回引用,不能返回值,因为要对同一原对象操作MyInteger& operator++() { 		//先++this->m_Num++;//再返回return *this;}private:int m_Num;
};/* 左移重载 */
ostream& operator<<(ostream& out, MyInteger myint) {out << myint.m_Num;return out;
}// 前置++ 先++ 再返回
void test01() {class MyInteger myInt;cout << ++myInt << endl; // 1 递增重载、左移重载cout << myInt << endl; // 1 左移重载
}int main() {test01();return 0;
}

后置++自增运算符

后置++, 只能返回值,因为创建的是临时对象,函数销毁,引用就不对了

#include <iostream>
using namespace std;
#include <string>/*前置递增返回引用,后置递增返回值
*/class MyInteger {friend ostream& operator<<(ostream& out, MyInteger myint);public:MyInteger() {m_Num = 0;}//后置++, 只能返回值,因为创建的是临时对象,函数销毁,引用就不对了MyInteger operator++(int) { // int 代表后置++ //先返回MyInteger temp = *this; // 记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;this->m_Num++;return temp;  // 此时返回的还是++前的 0}private:int m_Num;
};/* 左移重载 */
ostream& operator<<(ostream& out, MyInteger myint) {out << myint.m_Num;return out;
}//后置++ 先返回 再++
void test02() {MyInteger myInt;cout << myInt++ << endl; // 0cout << myInt << endl; // 1
}int main() {test02();return 0;
}

赋值运算符重载

  • =:将右操作数的值赋给左操作数。
  • +=:将左操作数与右操作数相加,并将结果赋给左操作数。
  • -=:将左操作数与右操作数相减,并将结果赋给左操作数。
  • *=:将左操作数与右操作数相乘,并将结果赋给左操作数。
  • /=:将左操作数与右操作数相除,并将结果赋给左操作数。

通过重载赋值运算符,您可以定义自定义类型的对象如何进行赋值操作。这使得对象可以通过使用等号和其他赋值运算符来进行赋值。

等号赋值运算符重

c++编译器至少给一个类添加4个函数

  1.  默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符 operator=, 对属性进行值拷贝

如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题

如果是浅拷贝,不做赋值重载深拷贝,那么每个类对象都会执行释放,但已释放的空间二次释放就会报错

class Person
{
public:Person(int age){// 将年龄数据开辟到堆区m_Age = new int(age);}// 重载赋值运算符 返回自身引用Person& operator=(Person &p){if (m_Age != NULL){delete m_Age;m_Age = NULL;}// 编译器提供的代码是浅拷贝//m_Age = p.m_Age;// 提供深拷贝 解决浅拷贝的问题m_Age = new int(*p.m_Age); // 各自指向各自的空间//返回自身return *this;}~Person() // 析构函数{if (m_Age != NULL){delete m_Age; // 如果是浅拷贝,不做赋值重载深拷贝,那么每个类对象都会执行释放,同一个堆空间二次释放就会报错m_Age = NULL;}}//年龄的指针int *m_Age;};void test01()
{Person p1(18);Person p2(20);Person p3(30);p3 = p2 = p1; // 连续赋值操作,前提必须返回自身引用cout << "p1的年龄为:" << *p1.m_Age << endl; // 18cout << "p2的年龄为:" << *p2.m_Age << endl; // 18cout << "p3的年龄为:" << *p3.m_Age << endl; // 18
}int main() {test01();//int a = 10;//int b = 20;//int c = 30;//c = b = a;//cout << "a = " << a << endl;//cout << "b = " << b << endl;//cout << "c = " << c << endl;return 0;
}

关系运算符重载

  • ==:检查两个值是否相等,返回布尔值。
  • !=:检查两个值是否不相等,返回布尔值。
  • >:检查左操作数是否大于右操作数,返回布尔值。
  • <:检查左操作数是否小于右操作数,返回布尔值。
  • >=:检查左操作数是否大于或等于右操作数,返回布尔值。
  • <=:检查左操作数是否小于或等于右操作数,返回布尔值。

通过重载这些关系运算符,您可以定义自定义类型对象之间的比较操作。这使得您可以使用关系运算符来比较自定义类型的对象,并根据需要定义其比较规则。

相等 

class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;};bool operator==(Person & p) // 关系重载,相等{if (this->m_Name == p.m_Name && this->m_Age == p.m_Age){return true;}else{return false;}}};void test01()
{//int a = 0;//int b = 0;Person a("孙悟空", 18);Person b("孙悟空", 18);if (a == b){cout << "a和b相等" << endl; // a和b相等}else{cout << "a和b不相等" << endl;}}int main() {test01();return 0;
}

不等 

#include <iostream>
using namespace std;
#include <string>/* 重载关系运算符,可以让两个自定义类型对象进行对比操作 */class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;};bool operator!=(Person & p) // 关系重载,不等{if (this->m_Name == p.m_Name && this->m_Age == p.m_Age){return false;}else{return true;}}string m_Name;int m_Age;
};void test01()
{//int a = 0;//int b = 0;Person a("孙悟空", 18);Person b("孙悟空", 18);if (a != b){cout << "a和b不相等" << endl;}else{cout << "a和b相等" << endl; // a和b相等}
}int main() {test01();return 0;
}

函数调用运算符重载

  • 函数调用运算符 ()  也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
  • 仿函数没有固定写法,非常灵活

class MyPrint
{
public:void operator()(string text) // 函数调用运算符重载函数,注意是在 operator后加 (),当前是打印值{cout << text << endl;}};
void test01()
{//重载的()操作符 也称为仿函数MyPrint myFunc;myFunc("hello world"); // hello world
}class MyAdd
{
public:int operator()(int v1, int v2) // 函数调用运算符重载函数,当前是返回值{return v1 + v2;}
};void test02()
{MyAdd add;int ret = add(10, 10);cout << "ret = " << ret << endl; // 20// 匿名对象调用  MyAdd()是匿名对象,执行完当前行就会销毁,MyAdd()(100, 100)是匿名对象调用重载函数cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}int main() {test01();test02();return 0;
}

总结

需要注意的是,虽然运算符重载提供了强大的功能,但滥用它可能会导致代码难以理解和维护。因此,对于每个运算符,都需要仔细考虑是否有必要进行重载,以及如何遵循最佳的代码设计和风格约定。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jmeter,csv文件参数化+断言 实现一个接口的case

1、case 及其 测试数据 注意保存文件的编码格式 id,name,limit,status,address,start_time,assert_status,assert_message 100,小米100,1000,1,某某会展中心101,2023-8-20 14:20,200,add event success ,,,,,,10021,parameter error 100,小米102,1002,1,某某会展中心103,2023-…

Centos7部署SVN

文章目录 &#xff08;1&#xff09;SVN概述&#xff08;2&#xff09;SVN与Samba共享&#xff08;3&#xff09;安装SVN&#xff08;4&#xff09;SVN搭建实例&#xff08;5&#xff09;pc连接svn服务器&#xff08;6&#xff09;svn图标所代表含义 &#xff08;1&#xff09;…

ArrayList与LinkLIst

ArrayList 在Java中&#xff0c;ArrayList是java.util包中的一个类&#xff0c;它实现了List接口&#xff0c;是一个动态数组&#xff0c;可以根据需要自动增长或缩小。下面是ArrayList的一些基本特性以及其底层原理的简要讲解&#xff1a; ArrayList基本特性&#xff1a; 动…

听GPT 讲Rust源代码--src/tools(13)

File: rust/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs 在Rust源代码中&#xff0c;路径为rust/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs的文件是为了处理Rust代码中的不一致实现问题而存在的。…

生成小程序URLlink链接遇到的坑

这里写自定义目录标题 前端生成小程序URL link背景用户打开小程序的常用方法短链接短链接优缺点优点缺点 生成短链接步骤 可能会遇到的问题&#xff1a;其他 注意&#x1f4e2; 前端生成小程序URL link ![h5打开小程序](https://img-blog.csdnimg.cn/direct/a4cfe3ef6d184c6d9…

MQTT的奇妙之旅:探索RabbitMQ Web MQTT插件的威力【RabbitMQ 十一】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 MQTT的奇妙之旅&#xff1a;探索RabbitMQ Web MQTT插件的威力 前言第一&#xff1a;揭秘RabbitMQ Web MQTT插件背景和目的&#xff1a;MQTT 协议简介&#xff1a;WebSockets 和 MQTT 的融合&#xff1…

让高清媒体无限畅享——Movist Pro for Mac推广文章

随着科技的迅猛发展&#xff0c;高清媒体已经成为我们日常生活中不可或缺的一部分。无论是观看电影、追剧、还是欣赏高清音乐视频&#xff0c;我们都希望能够获得最佳的视听体验。为了满足这一需求&#xff0c;我们向大家推荐一款强大的高清媒体播放器——Movist Pro for Mac。…

Selenium安装WebDriver:ChromeDriver与谷歌浏览器版本快速匹配_最新版120

最近在使用通过selenium操作Chrome浏览器时&#xff0c;安装中遇到了Chrome版本与浏览器驱动不匹配的的问题&#xff0c;在此记录安装下过程&#xff0c;如何快速找到与谷歌浏览器相匹配的ChromeDriver驱动版本。 1. 确定Chrome版本 我们首先确定自己的Chrome版本 Chrome设置…

【后端卷前端3】

侦听器 监听的数据是 data()中的动态数据~响应式数据 <template><div><p>{{showHello}}</p><button click"updateHello">修改数据</button></div> </template><script>export default {name: "goodsTe…

关于枚举的简单理解

1. 枚举的简单认识 1.1 枚举的引入 枚举是在JDK1.5以后引入的。主要用途是&#xff1a;将一组常量组织起来&#xff0c;在这之前表示一组常量通常使用定义常量的方式如下面的代码所示&#xff1a; public static final int RED 1; public static final int GREEN 2; public…

selenium 与 chromedriver安装

本文章向大家介绍selenium 安装与 chromedriver安装&#xff0c;主要包括selenium 安装与 chromedriver安装使用实例、应用技巧、基本知识点总结和需要注意事项供大家参考。 一、安装selenium 1、Selenium简介 Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开…

HNU-计算机网络-实验4-网络层与链路层协议分析(PacketTracer)

计算机网络 课程基础实验四网络层与链路层协议分析&#xff08;PacketTracer&#xff09; 计科210X 甘晴void 202108010XXX 文章目录 计算机网络 课程基础实验四<br>网络层与链路层协议分析&#xff08;PacketTracer&#xff09;一、实验目的二、实验内容4.1 路由器交换…

工业性能CCD图像处理+

目录 硬件部分 ​编辑 软件部分 CCD新相机的调试处理&#xff08;更换相机处理&#xff0c;都要点执行检测来查看图像变化&#xff09; 问题:新相机拍摄出现黑屏&#xff0c;图像拍摄不清晰&#xff0c;&#xff08;可以点击图像&#xff0c;向下转动鼠标的滚轮&#xff08…

NVIDIA A100 PCIE 40GB k8s-device-plugin install in kubernetes

文章目录 1. 目标2. 简介2.1 英伟达 A100 技术规格2.2 架构优势2.3 显卡跑分对比2.4 英伟达 A100 与 kubernetes 3. 安装 NVIDIA A100 GPU 40G 硬件4. NVIDIA R450 datacenter driver5. NVIDIA Container Toolkit6. 创建 runtimeclass5. MIG Strategies6. 配置仓库7. 下载镜像8…

【Java系列】详解多线程(三)—— 线程安全(上篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一…

人工智能在红斑狼疮应用主要以下4个方面

人工智能&#xff08;Artificial Intelligence, AI&#xff09;在医学领域的应用已取得了一定的进展。红斑狼疮&#xff08;Systemic Lupus Erythematosus, SLE&#xff09;是一种免疫系统性疾病&#xff0c;对该疾病进行诊断和治疗是一个复杂的过程。人工智能可以发挥作用&…

贝蒂详解<string.h>哦~(用法与实现)

目录 引言&#xff1a; &#xff08;一&#xff09;字符函数和字符串函数 1.简介 2.strlen()函数 2.1用法 2.2实例 2.3 实现strlen() &#xff08;1&#xff09;计数法 &#xff08;2&#xff09;递归法 &#xff08;3&#xff09; 指针-指针 2.4sizeof和strlen()的区别 3.s…

【Redis】Redis.conf详解

Redis.conf详解 启动的时候&#xff0c;就通过配置文件来启动&#xff01; 工作中&#xff0c;一些小小的配置&#xff0c;可以让你脱颖而出&#xff01; 单位 配置文件 unit单位 对大小写不敏感&#xff01;include包含其他配置文件 就是好比我们学习Spring、Improt&#x…

2023自动化测试框架大对比:哪个更胜一筹?

所谓工欲善其事&#xff0c;必先利其器&#xff0c;在进行自动化测试时&#xff0c;选择一个合适的框架是至关重要的。因为一个好的测试框架可以大大提高测试效率&#xff0c;减少我们很多工作量。在选择框架之前&#xff0c;我们通常需要对不同的框架进行对比&#xff0c;以便…

MC-30A (32.768 kHz用于汽车应用的晶体单元)

MC-30A 32.768 kHz用于汽车应用的晶体&#xff0c;车规晶振中的热销型号之一。该款石英晶体谐振器&#xff0c;可以在-40 to 85 C的温度内稳定工作&#xff0c;能满足起动振动的要求。同时满足AEC-Q200无源元件质量标准认证&#xff0c;满足汽车仪表系统的所有要求。 频率范围…