【浅尝C++】运算符重载(含类的3大默认成员函数:赋值、取地址、const对象取地址运算符重载)

news2024/11/19 13:40:45

在这里插入图片描述

🎈归属专栏:浅尝C++
🚗个人主页:Jammingpro
🐟记录一句:在Linux与C++中来回横跳,哪个学累了,就去学另外一个~~


文章前言:本篇文章简要介绍C++的运算符重载,同时接着上一篇文章,继续介绍类的余下3个成员函数,即赋值运算符重载、普通对象取地址运算符重载、const对象取地址运算符重载。


文章目录

  • 赋值运算符重载
    • 运算符重载
    • 赋值运算符重载
    • 前置后置++及--重载
  • 普通对象及const对象取地址运算符重载


我们知道,如果一个类什么都没有,那么它就是一个空类。空类真的什么都没有吗?答案是否定的。任何类在什么都不写时,编译器会自动生成下图的6个默认成员函数,上一篇文章已经介绍了构造函数、析构函数及拷贝构造函数,这一篇文章将介绍余下的3个默认成员函数。👇
ps:默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
在这里插入图片描述

赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号
函数原型:返回值类型 operator操作符(参数列表)

注意:
①不能通过连接其他符号来创建新的操作符:比如operator@ (必须是C++中已经存在的运算符,其他符号不能重载)
②重载操作符必须有一个类类型参数 (即调用重载运算符的变量,其中一个必须是类类型)
③用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
④作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this(第一个参数是类对象自身,不需要用户显示传入,编译器会自动传入该对象的this指针)。
.*::sizeof?:. 注意以上5个运算符不能重载。

下面我们实现一个复数类,并在类内重载==运算符👇

#include <iostream>
using namespace std;

class Complex
{
public:
	Complex(double r, double i)
	{
		_real = r;
		_imag = i;
	}
	bool operator==(const Complex& obj)
	{
		return _real == obj._real && _imag == obj._imag;
	}
private:
	double _real;
	double _imag;
};

int main()
{
	Complex c1(1, 2);
	Complex c2(1, 2);
	if(c1 == c2)
		cout << "they are equal" << endl;
	else
		cout << "too bad" << endl;
	return 0;
}

可不可以不在类内实现呢?当然可以,我们可以写成下方所示的全局函数👇
ps:下面代码涉及到友元的概念,如果还不知道友元是什么,可以将复数的属性设为公有的(public),并将带friend关键字的行删除,这样操作代码仍可以正常运行。

#include <iostream>
class Complex
{
public:
	Complex(double r, double i)
	{
		_real = r;
		_imag = i;
	}
private:
	friend bool operator==(const Complex& c1, const Complex& c2);
	double _real;
	double _imag;
};

bool operator==(const Complex& c1, const Complex& c2)
{
	return c1._real == c2._real && c1._imag == c2._imag;
}

int main()
{
	Complex c1(1, 2);
	Complex c2(1, 2);
	if(c1 == c2)
		cout << "they are equal" << endl;
	else
		cout << "too bad" << endl;
	return 0;
}

赋值运算符重载

赋值运算符重载格式
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要符合连续赋值的含义
下面的复数类显示给出了赋值运算符重载,在下面代码注释中,将给出上面重载格式的详细描述👇

#include <iostream>
using namespace std;

class Complex
{
public:
	//复数类的构造函数
	Complex(double r, double i)
	{
		_real =r;
		_imag = i;
	}
	//复数类的拷贝构造函数
	Complex(const Complex& c)
	{
		_real = c._real;
		_imag = c._imag;
	}
	//赋值运算符重载
	//返回参数使用引用是为了提高效率,避免调用拷贝函数构造临时对象。这里也可以使用非引用返回
	//参数使用const是为了避免赋值过程中被修改,引用传递是为了提高效率
	Complex& operator=(const Complex& c)
	{
		//防止自己给自己赋值
		if(this != &c)
		{
			_real = c._real;
			_imag = c._imag;
			return *this;
			//返回*this,即返回当前赋值运算符左值对象自身
		}
	}private:
	double _real;
	double _imag;
}

赋值运算符只能重载成类的成员函数不能重载成全局函数
下面这段代码将赋值运算符重载为全局函数,下面代码在编译时将报错
原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

#include <iostream>
using namespace std;

class Complex
{
public:
	Complex(double r, double i)
	{
		_real = r;
		_imag = i;
	}
	Complex(const Complex& c)
	{
		_real = c._real;
		_imag = c._imag;
	}
private:
	friend Complex& operator=(const Complex& c1, const Complex& c2);
	double _real;
	double _imag;
};

Complex& operator=(const Complex& c1, const Complex& c2)
{
	if (&c1 != &c2)
	{
		c1._real = c2._real;
		c1._imag = c2._imag;
		return c1;
	}
}

int main()
{
	Complex c1(1, 2);
	Complex c2 = c1;
}

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝(即浅拷贝)。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像复数类这样的类是没必要的。跟拷贝构造函数一样,如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。像下面的Stack类就需要自己实现重载赋值运算符。

class Stack
{
public:
	Stack(int n)
	{
		m_mem = new char[n];
		m_size = 0;
		m_capacity = n;
	}
	Stack& operator=(const Stack& s)
	{
		m_mem = new char[s.m_capacity];
		strcpy(m_mem, s.m_mem);
		m_size = s.m_size;
		m_capacity = s.m_capacity;
		return *this;
	}
private:
	char* m_mem;
	int m_size;
	int m_capacity;
};

下面图片演示的是编译器自动生成的重载赋值函数,其为值拷贝(即浅拷贝)。导致两个Stack对象指向同一内存空间,当两个Stack对象生命周期结束后,将分别释放该内存空间,一个内存空间被重复释放,将导致错误。
在这里插入图片描述

前置后置++及–重载

既然上面将运算符重载讲解的差不多了,这里就顺带叙述以下前置后置++和–。前置和后置的区别在于:前置运算符重载无需参数,后置运算符重载需要一个占位参数。具体讲解内容将在下面的代码注释中给出👇

class Counter
{
public:
	Counter(int n)
	{
		storage = n;
	}
	//前置++运算符重载,参数列表无参数
	Counter& operator++()
	{
		storage++;
		return *this;
	}
	//后置++运算符,参数列表需要一个占位参数
	//后置运算符返回的是++之前的值,因此要先保存一份原来的值,而保存下来的值存储在临时变量中,因此不能返回引用
	Counter operator++(int)
	{
		Counter copy = *this;
		++storage;
		return copy;
	}
	//前后置--与上面同理
private:
	int storage;
}

从上面代码可以知道,后置运算符的效率低于前置运算符,因为后置运算符需要创建临时对象保存当前对象+1或-1前的状态。同时,由于保存对象原状态的变量为临时变量,函数执行结束后生命周期结束,因此只能使用值返回,不能使用引用返回。创建值返回的临时变量需要再调用1次宝贝构造函数。后置运算符共调用了2次拷贝构造函数创建2个临时对象,因此效率较低。

普通对象及const对象取地址运算符重载

这一部分的代码实现与上述运算符重载类似,这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载。直接上代码👇

class Complex
{
public:
	Complex* operator&()
	{
		return this;
	}
	const Complex* operator&() const//->这里函数后面的const相当于给this指针加上const属性,防止this指针指向的对象内容被修改
	{
		return this;
	}
private:
	double _real;
	double _imag;
}

上面出现了const关键字,我们这通过一些问题对const关键字做一些介绍:
①const对象可以调用非const成员函数吗?
const对象是不可以修改的,非const成员函数可以修改对象中的成员,显然const对象不可以调用非const成员函数。
②非const对象可以调用const成员函数吗?
非const对象的成员数值可以修改,既然可以修改,那么就可以调用const和非const的成员函数了。
③const成员函数内可以调用其它的非const成员函数吗?
const成员函数是为了不修改对象本身,而非const成员函数可以修改对象成员,因此,const成员函数内不可以调用其它的非const成员函数
④非const成员函数内可以调用其它的const成员函数吗?
非const成员函数内可以修改对象成员,因此它可以调其他任何的const和非const成员函数。


文章结语:这篇文章对C++中的运算符重载,同时接着上一篇文章,继续介绍类的余下3个成员函数,即赋值运算符重载、普通对象取地址运算符重载、const对象取地址运算符重载。
🎈欢迎进入浅尝C++专栏,查看更多文章。
如果上述内容有任何问题,欢迎在下方留言区指正b( ̄▽ ̄)d

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科研学习|论文解读——Deep learning for anomaly detection in log data: a survey

摘要 自动日志文件分析能够及早发现系统故障等相关事件。特别是&#xff0c;自学习异常检测技术能够捕捉日志数据中的模式&#xff0c;然后向系统操作员报告意外的日志发生&#xff0c;而无需提前提供或手动建模异常场景。最近&#xff0c;越来越多的利用深度学习方法来实现此目…

TikTok区块链实践:数字社交媒体的去中心化未来

随着区块链技术的日渐成熟&#xff0c;数字社交媒体行业也在探索如何整合区块链&#xff0c;以推动去中心化发展。在这一潮流中&#xff0c;TikTok作为全球领先的短视频平台&#xff0c;积极实践区块链技术&#xff0c;探索数字社交媒体的未来。本文将深入探讨TikTok的区块链实…

Message全局提示(antd-design组件库)简单用法

1.Message全局提示 全局展示操作反馈信息。 2.何时使用 可提供成功、警告和错误等反馈信息。 顶部居中显示并自动消失&#xff0c;是一种不打断用户操作的轻量级提示方式。 组件代码来自&#xff1a; 全局提示 Message - Ant Design 3.本地验证前的准备 参考文章【react项目ant…

Anolis 安装 Conda 和 YoloV8

Anolis 安装 Conda 和 YoloV8 一 Conda 和 YoloV8 安装1.Conda 下载与安装2.YoloV8 安装 二.测试 一 Conda 和 YoloV8 安装 ## 1. anolis 安装 cv2 依赖库 yum install -y mesa-libGL.x86_64 ## Anaconda https://repo.anaconda.com/archive/ ## 重启终端查看版本 conda --ver…

小航助学题库蓝桥杯题库c++选拔赛(21年3月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;

LoadRunner自动化测试工具的应用

目录 第一部分:Loadrunner的简介 1.1 安装注意事项 1.2 协议的选择或者 VUSER 类型的选取 1.3 LR 的基本原理 1.4 测试脚本录制/分配所遵循的几个原则 第二部分:录制脚本 2.1 录制脚本前需要理解的几个基本概念 2.1.1 事务(Transaction) 2.1.2 集合点(Rendezvous) 2.1…

本地部署GPT的实战方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

【动态规划】LeetCode-70.爬楼梯

&#x1f388;算法那些事专栏说明&#xff1a;这是一个记录刷题日常的专栏&#xff0c;每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目&#xff0c;在这立下Flag&#x1f6a9; &#x1f3e0;个人主页&#xff1a;Jammingpro &#x1f4d5;专栏链接&…

推荐一款好用的BMP转PNG工具BMP2PNG

推荐一款好用的BMP转PNG工具BMP2PNG 自己写的一个BMP转PNG工具BMP2PNG 写这个工具是因为要使用传奇的部分素材在COCOS2DX使用&#xff0c; 但是COCOS2DX不支持BMP 如果直接将BMP转换到PNG的话&#xff0c;网上找到的工具都不支持透明色转换。难道要用PS一个一个抠图吗&#xf…

ESD静电试验方法及标准

文章目录 概述静电放电抗扰标准静电放电实验室的型式试验静电放电试验配置静电放电试验方法 静电放电等级 参考静电放电发生器&#xff08;ESD&#xff09;试验方法及标准 概述 在低湿度环境下通过摩擦使人体充电的人体在与设备接触时可能会放电&#xff0c;静电放电的后果是&…

虹科分享 | 平衡速度和优先级:为多样化的实时需求打造嵌入式网络(4)——从理论到实践:CANopen源代码配置

正如前文所述&#xff0c;CANopen的适应性在满足实时应用需求方面发挥着至关重要的作用。本系列文章的最后一部分将向您展示 CANopen 源代码配置的技术细节&#xff0c;以及实现高效实时性能的优化方法。 前文回顾&#xff1a; 虹科分享 | 平衡速度和优先级&#xff1a;为多样…

【VUE】el-tab相关问题

Tabs 标签页 分隔内容上有关联但属于不同类别的数据集合。 <template><el-tabs v-model"activeName" tab-click"handleClick"><el-tab-pane label"用户管理" name"first">用户管理</el-tab-pane><el-tab-p…

思维模型 热炉效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。对违规行为零容忍。 1 热炉效应的应用 1.1 热炉效应管理应用-谷歌公司 谷歌公司在员工管理中采用了“热炉效应”的原则。当员工违反公司政策或行为准则时&#xff0c;谷歌会采取严厉的措施…

数据库系统原理——备考计划2:数据库系统的概述

前言&#xff1a; 基于课本、上课ppt、复习总结ppt进行一个知识点的罗列&#xff0c;方便后期高效地复习 目录 前言&#xff1a; 一、基本概念 1.数据&#xff1a; &#xff08;1&#xff09;概念&#xff1a; &#xff08;2&#xff09;数据的种类&#xff1a; &#xff08;3&…

【UE】夜视仪效果

效果 步骤 1. 新创建一个空白项目&#xff0c;勾选“光线追踪”选项 新建一个Open World关卡 添加一个“第一人称游戏”到项目 将角色蓝图放入场景中 设置自动控制玩家 2. 打开第一人称角色蓝图“BP_FirstPersonCharacter”&#xff0c;添加一个后期处理组件&#xff0c;该组件…

运维知识点-SQLServer/mssql

SQLServer/mssql Microsoft structed query language常见注入提权 技术点&#xff1a;0x00 打点前提 0x01 上线CS0x02 提权0x03 转场msf0x04 抓取Hash0x05 清理痕迹 Microsoft structed query language 常见注入 基于联合查询注入 order by 判断列数&#xff08;对应数据类型…

C++二分查找算法:包含每个查询的最小区间

本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个二维整数数组 intervals &#xff0c;其中 intervals[i] [lefti, righti] 表示第 i 个区间开始于 lefti 、结束于 righti&#xff08;包含两侧取值&a…

【Lustre相关】应用部署-03-Lustre集群部署实践(软raid方案)

文章目录 一、前言1、硬件配置2、组网拓扑3、总体方案 二、软件安装三、集群部署1、配置多路径2、配置高可用集群3、配置zpool4、部署lustre5、配置Lustre角色高可用6、配置Lustre状态监控6.1、Lustre网络状态监控6.2、Lustre集群状态监控6.3、配置优化6.3.1、设置故障恢复不回…

7Docker搭建es和kibana

一、安装es 1.拉取镜像 sudo docker pull elasticsearch:7.12.0 elasticsearch:7.12.0:我安装的版本是7.12.0&#xff0c;可以根据实际的情况安装 创建docker容器挂在的目录&#xff1a; sudo mkdir -p /opt/elasticsearch/config sudo mkdir -p /opt/elasticsearch/data s…

TA-Lib学习研究笔记——Overlap Studies(二)上

TA-Lib学习研究笔记——Overlap Studies&#xff08;二&#xff09; 1. Overlap Studies 指标 [BBANDS, DEMA, EMA, HT_TRENDLINE, KAMA, MA, MAMA, MAVP, MIDPOINT, MIDPRICE, SAR, SAREXT, SMA, T3, TEMA, TRIMA, WMA]2.数据准备 get_data函数参数&#xff08;代码&#x…