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

C++ :运算符重载

运算符重载:

运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

 

运算符的重载实际是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该重载的运算符时调用此函数。这个函数叫做运算符重载函数,通常为类的成员函数

定义运算符重载函数的一般格式
返回值类型 类名::operator重载的运算符(参数表)  {.......}

operator是关键字,它与重载的运算符一起构成函数名。因函数名的特殊性,C++编译器可以将这类函数识别出来

加号运算符重载: 

作用:实现两个自定义数据类型相加的运算

1.成员函数实现 + 号运算符重载

 

#include <iostream>
using namespace std;//加号运算符重载class Person
{
public://1 成员函数实现 + 号运算符重载Person operator+(Person& p){Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}int m_A;int m_B;
};void test01() {Person p1;p1.m_A = 10;p1.m_B = 10;Person p2;p2.m_A = 10;p2.m_B = 10;Person p3 = p1 + p2;cout <<  "p3.m_A = " << p3.m_A<< endl;cout <<  "p3.m_B = " << p3.m_B<< endl;
}int main() {test01();system("pause");return 0;
}

(2).全局函数重载:

class Person
{
public://1 成员函数实现 + 号运算符重载/*Person operator+(Person& p){Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}*/int m_A;int m_B;
};//2.全局函数重载+号
Person operator+(Person& p1, const Person& p2)
{Person temp;temp.m_A = p1.m_A + p2.m_A;temp.m_B = p1.m_B + p2.m_B;return temp;
}//3 运算符重载 可以发生函数重载
Person operator+(Person& p1, int num)
{Person temp;temp.m_A = p1.m_A + num;temp.m_B = p1.m_B + num;return temp;
}void test01() {Person p1;p1.m_A = 10;p1.m_B = 10;Person p2;p2.m_A = 10;p2.m_B = 10;//成员函数方式Person p3 = p2 + p1; //相当于 p2.operaor+(p1)Person p3 = p1 + p2;//全局函数重载本质调用:Person p3 = operator+(p1, p2);Person p3 = p1 + p2;//cout <<  "p3.m_A = " << p3.m_A<< endl;cout <<  "p3.m_B = " << p3.m_B<< endl;
}int main() 
{test01();system("pause");return 0;
}

2.左移运算符重载

作用:可以输出自定义数据类型
#include <iostream>
using namespace std;//左移运算符重载class Person
{friend ostream& operator<<(ostream& cout, Person& p);public:Person(int a, int b){this->m_A = a;this->m_B = b;}
private:
//成员函数 实现不了  p << cout 不是我们想要的效果//void operator<<(Person& p){//}int m_A;int m_B;
};//全局函数实现左移重载
ostream& operator<<(ostream& cout, Person &p)  //本质 operator<<(cout,p) 简化cout<<p
{cout << "m_A = " << p.m_A << " m_B = " << p.m_B;return cout;
}void test01()  
{Person p(10,10);//p.m_A = 10;//p.m_B = 10;cout << p<<"hello world"<<endl; //链式编程   输出一个对象就能打印他的属性
} int main() 
{test01();system("pause");return 0;
}

总结:重载左移运算符配合友元可以实现输出自定义数据类型

3.递增运算符重载

作用: 通过重载递增运算符,实现自己的整型数据
总结:前置递增返回引用,后置递增返回值
先写一个输出整形数据的:

class MyInteger 
{friend ostream& operator<<(ostream& cout, MyInteger myint);
public:MyInteger() {m_Num = 0;}private:int m_Num;
};//重载左移运算符
ostream& operator<<(ostream& cout, MyInteger myint)
{cout << myint.m_Num << endl;    //全局函数想要访问私有属性return cout;
}
void test01()
{MyInteger myint;cout << myint << endl;}int main() 
{test01();system("pause");return 0;
}

输出结果: 0

 

class MyInteger 
{friend ostream& operator<<(ostream& cout, MyInteger myint);
public:MyInteger() {m_Num = 0;}//重载前置++运算符 返回引用为了一直对一个数据进行递增操作MyInteger& operator++(){//先++m_Num++;//再返回return *this;}//重载后置++运算符  //int代表占位参数,可以用于区分前置和后置递增MyInteger operator++(int){//先记录当时结果MyInteger temp = *this;//后递增m_Num++;//最后将记录结果做返回return temp;}private:int m_Num;
};//重载左移运算符
ostream& operator<<(ostream& cout, MyInteger myint)
{cout << myint.m_Num << endl;    //全局函数想要访问私有属性return cout;
}
void test01()
{MyInteger myint;cout << ++myint << endl;}void test02()
{MyInteger myint;cout << myint++ << endl;cout << myint << endl;
}int main() 
{// test01();test02();system("pause");return 0;
}

4.赋值运算符重载: 

c++ 编译器至少给一个类添加 4 个函数
1. 默认构造函数 ( 无参,函数体为空 )
2. 默认析构函数 ( 无参,函数体为空 )
3. 默认拷贝构造函数,对属性进行值拷贝
4. 赋值运算符 operator=, 对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
class Person
{
public:Person(int age){m_Age = new int(age);  //把数据创建在堆区 }~Person(){if (m_Age != NULL){delete m_Age;m_Age = NULL;}}                           //释放堆区内存  int* m_Age;};void test01()
{Person p1(18);Person p2(20);p2 = p1;    //赋值操作cout << "p1的年龄为:" << *p1.m_Age << endl;cout << "p2的年龄为:" << *p2.m_Age << endl;
}int main()
{test01();system("pause");return 0;
}

上示代码会崩;

 崩溃原因:堆区内存重复释放

 

解决方法: 

 示例如下:

class Person
{
public:Person(int age){m_Age = new int(age);  //把数据创建在堆区 }~Person(){if (m_Age != NULL){delete m_Age;m_Age = NULL;}}                           //释放堆区内存  //重载 赋值运算符    (编译器默认提供) 是一个浅拷贝的操作,创建在堆区d的属性,就会出现堆区内存重复释放Person& operator=(Person &p)  //返回引用{//编译器提供的代码是浅拷贝//m_Age = p.m_Age;//应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝if (m_Age != NULL){delete m_Age;m_Age = NULL;}//提供深拷贝 解决浅拷贝的问题m_Age = new int(*p.m_Age);//返回自身  为了实现连等return *this;}int* m_Age;        //创建在堆区};void test01()
{Person p1(18);Person p2(20);Person p3(30);p3 = p2 = p1; //赋值操作cout << "p1的年龄为:" << *p1.m_Age << endl;cout << "p2的年龄为:" << *p2.m_Age << endl;cout << "p3的年龄为:" << *p3.m_Age << endl;}int main()
{test01();system("pause");return 0;
}

拷贝构造函数 与赋值重载函数的区别。
总结: 浅赋值与深复制。
什么时候使用深拷贝和深赋值。
在类型设计中,使用动态内存或使用内核对象时,必须重新实现拷贝构造函数和赋值重载 

 5.关系运算符重载:

作用: 重载关系运算符,可以让两个自定义类型对象进行对比操作
如下图,对于内置类型来说,编译器可以正常运行,但是对于自定义类型来说,程序会出现崩溃现象。
class Person
{
public:Person(string name, int age)   //用构造函数进行赋初值{m_Name = name;m_Age = age;}string m_Name;int m_Age;};void test01()
{Person p1("Tom", 18);Person p2("Tom", 18);if (p1 == p2)  、//err{cout << "a和b相等" << endl;}else{cout << "a和b不相等" << endl;}
}int main()
{test01();system("pause");return 0;
}

对于== 

重载关系运算符,可以让两个自定义类型对象进行对比操作 

class Person
{
public:Person(string name, int age)   //用构造函数进行赋初值{m_Name = name;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;}}string m_Name;int m_Age;};void test01()
{Person p1("Tom", 18);Person p2("Tom", 18);if (p1 == p2)   //err 需要重载=={cout << "p1和p2相等" << endl;}else{cout << "p1和p2不相等" << endl;}
}int main()
{test01();system("pause");return 0;
}

 对于!= 

class Person
{
public:Person(string name, int age)   //用构造函数进行赋初值{m_Name = name;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;}}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()
{Person p1("Tom", 18);Person p2("Jerry", 18);if (p1 == p2)   //err 需要重载=={cout << "p1和p2相等" << endl;}else{cout << "p1和p2不相等" << endl;}if (p1 != p2)   //err 需要重载=={cout << "p1和p2是不相等" << endl;}else{cout << "p1和p2相等" << endl;}
}int main()
{test01();system("pause");return 0;
}

运行结果:

 

6.函数调用运算符重载

函数调用运算符 () 也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活
//打印输出类
class MyPrint
{
public://重载函数调用运算符 也称为仿函数void operator()(string test)  //()代表了函数名 (string test) 形参列表{cout << test << endl;}
};void MyPrint02(string test)
{cout << test << endl;
}void test01()
{MyPrint myPrint;myPrint("hello world");//由于使用起来非常类似于函数调用,因此称为仿函数MyPrint02("hello world");      //函数调用
}//仿函数非常灵活 没有固定的写法  依照需求 写对应的仿函数
//加法类class MyAdd  //实现两数相加
{
public:int operator()(int num1,int num2){return num1 + num2;}
};void test02()
{MyAdd myadd;   //先创建对象int ret = myadd(100, 100);cout << "ret = " << ret << endl;//匿名对象调用  类型加小括号cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}int main() 
{test01();//test02();system("pause");return 0;
}

运算符重载函数的总结:


1、运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时,将右操作数作为函数的实参。
2、当用类的成员函数实现运算符的重载时,运算符重载函数的参数(当为双目运算符时)为一个或(当为单目运算符时)没有。运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函数,而右操作数是该函数的参数。
3、单目运算符“++”和“"存在前置与后置问题.

前置“++"格式为:
返回类型 类名::operator++(){......}
而后置“++"格式为:
返回类型 类名::operator++(int){......}
后置“++”中的参数int仅用作区分,并无实际意义,可以给一个变量名,也可以不给变量名。

4、C++中只有极少数的运算符不允许重载

重载运算符有以下几种限制:
不可臆造新的运算符.
不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数.
运算符重载不宜使用过多
重载运算符含义必须清楚,不能有二义性 

相关文章:

C++ :运算符重载

运算符重载&#xff1a; 运算符重载概念&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 运算符的重载实际是一种特殊的函数重载&#xff0c;必须定义一个函数&#xff0c;并告诉C编译器&#xff0c;当遇到该重载的运算符…...

如何跑通跨窗口渲染:multipleWindow3dScene

New 这是一个跨窗口渲染的示例&#xff0c;用 Three.js 和 localStorage 在同一源&#xff08;同产品窗口&#xff09;上跨窗口设置 3D 场景。而这也是本周推特和前端圈的一个热点&#xff0c;有不少人在争相模仿它的实现&#xff0c;如果你对跨窗口的渲染有兴趣&#xff0c;可…...

flutter-web中使用js工具类

文章目录 为什么要调用js1. flutter-web1. 引入js web/index.html2. 创建工具js web/CryptoEnc.js3. 创建对应的lib/js/js_interop.dart4. 由于引入的js是针对web平台的&#xff0c;所以引入需要做引入处理5. 使用 2. Android1. 引入依赖2. index.html3. dart引用 为什么要调用…...

@ResponseBody详解:用于响应体响应数据

RestFul风格或者是web阶段接触过的异步请求&#xff0c;都需要把数据转换成Json放入响应体中。 ResponseBody的作用其实是将java对象转为json格式的相应内容 使用 RequestMapping注解时&#xff0c;Spring会将返回值解析为视图路径&#xff0c;然后跳转路径返回对应的视图页面…...

【Python百练——第3练】矩形类及操作

&#x1f490;作者&#xff1a;insist-- &#x1f490;个人主页&#xff1a;insist-- 的个人主页 理想主义的花&#xff0c;最终会盛开在浪漫主义的土壤里&#xff0c;我们的热情永远不会熄灭&#xff0c;在现实平凡中&#xff0c;我们终将上岸&#xff0c;阳光万里 ❤️欢迎点…...

【C语言学习疑难杂症】C语言中数组存储时为什么从低地址到高地址

在C语言中&#xff0c;数组的存储从低地址到高地址是有其历史原因的。这种设计主要是为了与计算机系统的内存组织方式相一致。 在计算机系统中&#xff0c;内存通常按照字节进行编址&#xff0c;地址从低到高递增。数组在内存中是连续存储的&#xff0c;因此数组的第一个元素&…...

Linux:查看端口占用的进程

命令 netstat -tunlp可以从图中看到&#xff0c;端口被那个进程占用&#xff0c;对应进程的pid是多少。...

医美店会员管理系统预约小程序作用是什么

医美在美业中占据着一定地位&#xff0c;爱美使然和经济独立、悦己消费下&#xff0c;不少女性会前往医美机构做脸部整容、嫩肤补水等服务&#xff0c;如美容院一样都是具备本地外地属性的&#xff0c;因此在如今互联网盛行下&#xff0c;商家需要借势线上破解难题及增强生意效…...

Linux 正则表达式

内容概述 1 文本编辑工具之神 VIM 1.1 vi 和 vim 简介 在 Linux 中我们经常编辑修改文本文件&#xff0c;即由 ASCII Unicode 或者其他编码的纯文字的文件。之前介绍过的 nano&#xff0c;实际工具中我们使用更为专业&#xff0c;功能强大的工具 文本编辑种类&#xff1a; vi…...

C语言面试之数组指针上篇

C语言数组是C语言中重要的数据结构之一&#xff0c;它用于存储一组相同类型的数据。数组在C语言中是以连续的内存空间来存储的&#xff0c;每个数组元素都是一个变量&#xff0c;占据一定的内存空间&#xff0c;数组元素之间是紧密相邻的。 一、数组的定义 在C语言中&#xff0…...

LinkWeChat,唯一以开源为核心的SCRM

LinkWeChat是国内首个基于企业微信的开源SCRM&#xff0c;在集成了企微强大的开放能力的基础上&#xff0c;进一步升级拓展灵活高效的客户运营能力及多元化精准营销能力&#xff0c;让客户与企业之间建立强链接&#xff0c;帮助企业提高客户运营效率&#xff0c;强化营销能力&a…...

Android textView 显示: STRING_TOO_LARGE

在Android中&#xff0c;字符串资源的长度限制是32KB&#xff0c;getString()方法返回的字符串资源的大小超过这个限制&#xff0c;就会抛出STRING_TOO_LARGE 这个错误。 我本地的临界值是&#xff1a;32.3 KB (33,090 字节) 小于等于33090时&#xff0c;能正常显示&#xff…...

用HeidiSQL在MySQL中创建新的数据库

用有权限的用户登录&#xff1a; 右键单击&#xff0c;选择&#xff1a; 输入要创建的数据库名称&#xff0c;然后点击“确定”&#xff1a; 刷新下&#xff0c;就看到新创建的数据库了&#xff1a; 在新创建的数据库中&#xff0c;就可以做其它操作了&#xff0c;例如…...

纯前端实现导入excel数据

准备工作 - 下载 xlsx npm install xlsx下面直接上代码&#x1f447; <template><div><input type"file" accept".xlsx, .xls" change"handleClick"></div> </template><script langts setup> import * a…...

Matlab下载许可证文件 教程(在账号有许可证的前提下)

文章目录 Part.I IntroductionPart.II 许可证文件过期解决方案Chap.I 使用 Internet 自动激活Chap.II 在不使用 Internet 的情况下手动激活 Part.I Introduction 本文主要介绍&#xff0c;在 Mathwork 账号有许可证的前提下&#xff0c;下载许可证的操作流程。 好久没有用 Mat…...

AI 绘画 | Stable Diffusion 电商模特

前言 上一篇文章讲到如何给人物更换背景和服装。今天主要讲电商模特,就是服装电商们的固定服装产品图片如何变成真人模特穿上的固定服装产品效果图。如果你掌握了 《AI 绘画 | Stable Diffusion 人物 换背景|换服装》,这篇文章对你来说,上手会更轻松。 教程 提取服装蒙版…...

vue面试题整理(1.0)

一、对MVC&#xff0c;MVP&#xff0c;MVVM的理解 三者都是项目的架构模式&#xff08;不是类的设计模式&#xff09;&#xff0c;即&#xff1a;一个项目的结构&#xff0c;如何分层&#xff0c;不同层负责不同的职责。 1.MVC MVC的出现是用在后端&#xff08;全栈时代&…...

PyQt基础_007_ 按钮类控件QCombox

import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class ComboxDemo(QWidget):def __init__(self, parentNone):super(ComboxDemo, self).__init__(parent)self.setWindowTitle("combox 例子") self.resize(300, 90) …...

Android Wifi的扫描机制

Android Wifi 的扫描场景分为下面四种情况&#xff1a; 1.亮屏情况下&#xff0c;在Wifi settings界面&#xff0c;固定扫描&#xff0c;扫描时间为10s。 2.亮屏情况下&#xff0c;在非Wifi settings界面&#xff0c;二进制指数退避扫描&#xff0c;退避&#xff1a;interval…...

类 —— 友元、常/静态成员函数

类 类的大小 和结构体大小求法一致。但需注意&#xff0c;普通空类也会占用 1 字节大小&#xff0c;因为普通空类可以实例化对象。 而 抽象空类占 4 字节&#xff08;32 位机中&#xff09;&#xff0c;因为抽象空类中含有虚指针&#xff08;含有虚函数的非抽象空类同理&am…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...