C++——类和对象(三)

news2024/11/23 10:25:58

一.赋值运算符

1.运算符重载

(1) 运算符重载是具有特殊名字的函数,他的名字是由operator和后面要定义的运算符共同构成。和其他函数一样,它也具有其返回类型和参数列表以及函数体

(2) 重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。一元运算符有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数右侧运算对象传给第二个参数。

(3) 如果⼀个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少⼀个。

(4) 不能通过连接语法中没有的符号来创建新的操作符:比如operator@。

(5) .*   ::   sizeof     ?:   注意以上5个运算符不能重载。

(6) 重载操作符至少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义

(7) 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,方便区分。

(8) 重载>>和<<时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第一个形参位 置,第一个形参位置是左侧运算对象, 调用时就变成了对象<<cout不符合使用习惯和可读性。 重载为全局函数把ostream/istream放到第一个形参位置就可以了,第二个形参位置当类类型对象。

int  operator+(int x, int y)
{
	return x + y;
}

以上是一个错误的代码,通过这个代码也解释了第6条,必须有一个参数是类类型。

bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day;
}

这个才是正确的写法,其中的一个参数是类类型。 

Date d1(2024, 10, 12);
Date d2(2024, 10, 13);
operator==(d1, d2);//第一种方式
d1 == d2;//第二种方式

这是对operator的调用,有两种方式。

class Date
{
public:
	bool operator==(const Date& d1)
	{
		return d1._year == _year && d1._month == _month && d1._day == _day;
	}
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	//private:
	int _year;
	int _month;
	int _day;
};

当我在类里面书写一个运算符重载时,当有两个参数,我只需要写一个即可,当有一个参数,我可以不写,因为第三条解释了,有一个隐含的this指针。 

Date d1(2024, 10, 12);
Date d2(2024, 10, 13);
d1.operator==(d2);//第一种方法
d1 == d2;//第二种方法

当我写在类里面的时候,也是有两种方法,但是与上面的两种略有不同。

Date operator++(int)
{
	cout<<"后置++" << endl;
	Date tem = *this;
	_day++;
	return tem;
}
Date& operator++()
{
	cout << "前置++" << endl;
	_day++;
	return *this;
}

在后置++中加入的int形参可以不写参数名,因为我们并不需要传值,只是与前置++区分而已。

如果对这里的*this不太理解的话,可以看 C++----类和对象(一)-CSDN博客来了解。

Date d1(2024, 10, 13);
Date d2(2024, 10, 13);
Date tem1 = d1++;
Date tem2 = ++d2;
d1.Print();
tem1.Print();
d2.Print();
tem2.Print();

这是一个测试代码。 

 

可以看到tem1是后置++,所以得到的是++之前的值,而tem2是前置++,所以得到的是++后的值。 

如果我想写一个输出Date的年月日的重载运算符。

当我写在类里面时

void operator<<(ostream& out)
{
	out << _year <<"年"<< _month <<"月"<< _day<<"日" << endl;
}

 那么代码就是以上的情况(不要忘记有隐藏的this指针)

但是当我要调用的时候,我写成这样

这样写是错误的,为什么呢?

因为这里已经进行了规定,当我写在类里面的时候,隐含了一个this,并且这个this在第一个参数的位置,根据第二条规定, 二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。所以我的左侧应该写一个Date类型的参数

Date d1(2024, 10, 13);
d1 << cout;

所以这样才是正确的写法,但是这样写又太别扭了。那么我们应该怎么写呢? 

这样我们只可以写在全局的函数了。

void operator<<(ostream& out,const Date& d1  )
{
	out << d1._year << "年" <<d1. _month << "月" <<d1. _day << "日" << endl;
}

但是这样存在一个问题

 

因为我们的成员都是private的类型,在外面访问不到,所以我们要先了解一个用法,以后我会详细的讲解。

friend void operator<<(ostream& out, const Date& d1);

将这个写在类的任意位置即可,这样我们便可以访问类里面的成员。

那么我想要连续的输出成员的年月日呢?

ostream& operator<<(ostream& out,const Date& d1)
{
	out << d1._year << "年" <<d1. _month << "月" <<d1. _day << "日" << endl;
	return out;
}

我们只要把他的返回值改变就可以。

 

因为返回值是ostream的流,所以当输出d1后,他们就会返回cout,变成cout<<d2,在输出d2。 

注意:当调用ostream或者istream两个流的时候,我们一定要用引用。 

 2.赋值运算符

赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值,这里要注意跟拷贝构造区分,拷贝构造用于⼀个对象拷贝初始化给另一个要创建的对象。

赋值运算符重载的特点:

1. 赋值运算符重载是一个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const当前类类型引用,否则会传值传参会有拷贝 

2. 有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景。

3. 没有显式实现时,编译器会自动生成⼀个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷贝构造函数类似,对内置类型成员变量会完成值拷贝/浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量会调用他的赋值重载函数。

4. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器自动生成的赋值运算符重载就可以完成需要的拷贝,所以不需要我们显示实现赋值运算符重载。像ST这样的类,虽然也都是内置类型,但是_a指向了资源,编译器自动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。像NEW这样的类型内部主要是自定义类型ST成员,编译器自动生成的赋值运算符重载会调用ST的赋值运算符重载也不需要我们显示实现NEW的赋值运算符重载。这里还有⼀个一技巧,如果⼀个类显示实现了析构并释放资源,那么他就需要显示写赋值运算符重载,否则就不需要。

代码的实现 :

void operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

 

这便是赋值运算符的应用。 

Date d1(2024, 10, 13);
Date d2(2024, 10, 12);
d2 = d1;
d2.Print();
Date d3 = d1;
d3.Print();

 

这里有两个等号,但是意义不相同,第一个是赋值运算符,第二个是拷贝构造

怎么区分呢?

拷贝构造是一个对象对另一个对象进行初始化,

而赋值重载是两个已经初始化好的对象进行拷贝。 

Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
	cout << "拷贝构造" << endl;
}
void operator=(const Date& d)
{
	cout << "这是赋值重载" << endl;
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

 

以下是全部代码:

#include<iostream>
using namespace std;
class Date
{
public:
	bool operator==(const Date& d1)
	{
		return d1._year == _year && d1._month == _month && d1._day == _day;
	}
	Date operator++(int)
	{
		cout<<"后置++" << endl;
		Date tem = *this;
		_day++;
		return tem;
	}
	Date& operator++()
	{
		cout << "前置++" << endl;
		_day++;
		return *this;
	}
	void operator<<(ostream& out)
	{
		out << _year <<"年"<< _month <<"月"<< _day<<"日" << endl;
	}
	friend ostream& operator<<(ostream& out, const Date& d1);
	void operator=(const Date& d)
	{
		cout << "这是赋值重载" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		cout << "拷贝构造" << endl;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out,const Date& d1)
{
	out << d1._year << "年" <<d1. _month << "月" <<d1. _day << "日" << endl;
	return out;
}

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

React.createRef(),React.forwardRef(),forwardRef()结合next.js的link进行路由跳转

码云https://gitee.com/skyvilm/react-next.js 1.React.createRef() 作用&#xff1a;获取dom元素 使用 import React,{Component} from react export default class Index extends Componen{ constructor(props){ super(props) this.myrefReact.createRef(); //创建节点 } c…

如何批量从sql语句中提取表名

简介 使用的卢易表 的提取表名功能&#xff0c;可以从sql语句中批量提取表名。采用纯文本sql语法分析&#xff0c;无需连接数据库&#xff0c;支持从含非sql语句的文件文件中提取&#xff0c;支持各类数据库sql语法。 特点 快&#xff1a;从成百个文件中提取上千个表名只需1…

集成方案 | 借助 Microsoft Copilot for Sales 与 Docusign,加速销售流程!

加速协议信息提取&#xff0c;随时优化邮件内容~ 在当今信息爆炸的时代&#xff0c;销售人员掌握着丰富的数据资源。他们能够通过 CRM 平台、电子邮件、合同库以及其他多种记录系统&#xff0c;随时检索特定个人或组织的关键信息。这些数据对于销售沟通至关重要。然而&#x…

【端到端】CVPR 2023最佳论文:UniAD解读

作者&#xff1a;知乎一根呆毛授权发布 传统的端到端网络是用多个小model串起来&#xff0c;但这会有误差累积的问题&#xff0c;因此我们提出了UniAD&#xff0c;一个综合框架&#xff0c;把所有任务整合到一个网络。整一个网络都是为planner而进行设计的。 Introduction a传…

SQL性能优化指南:如何优化MySQL多表join场景

目录 多表join问题SQL 这里解释下 Using join buffer (Block Nested Loop)&#xff1a; 对性能产生的影响&#xff1a; 三种join算法介绍 join操作主要使用以下几种算法&#xff1a; &#xff08;1&#xff09;Nested Loop Join &#xff08;2&#xff09;Block Nested …

生信服务器配置:优化生物信息学数据处理的最佳实践

介绍 在生物信息学研究中&#xff0c;处理和分析大规模数据集&#xff08;如基因组、转录组和蛋白质组数据&#xff09;需要强大的计算资源和精确的服务器配置。生信服务器配置的优化可以显著提高数据处理的效率和结果的准确性。本文将探讨生信服务器配置的关键要素&#xff0…

【LeetCode热题100】分治-快排

本篇博客记录分治快排的4道题目&#xff1a;颜色分类、排序数组、数组中的第K个最大元素、数组中最小的N个元素&#xff08;库存管理&#xff09;。 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int left -1,right n;for(int…

【实战项目】——Boost搜索引擎(五万字)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、项目的相关背景 1.1、什么是Boost库&#xff1f; 1.2、什么是搜索引擎&#xff1f; 1.3、为什么要做Boost库搜索引擎&#xff1f; 二、搜索引擎的宏观原…

VirtualBOX虚拟机提高速度,鼠标卡顿解决——未来之窗数据恢复

一、刚安装完操作系统&#xff0c;鼠标操作不灵敏 需要安装系统增强 二、系统增强作用 1.鼠标丝滑 2.文件共享 3.可以共享剪贴板 三、安装步骤-设备-安装增强 四、安装步骤-设备-选择光驱 五、安装增强软件然后重启 六、阿雪技术观 拥抱开源与共享&#xff0c;见证科技进…

【算法】动态规划:从斐波那契数列到背包问题

【算法】动态规划&#xff1a;从斐波那契数列到背包问题 文章目录 【算法】动态规划&#xff1a;从斐波那契数列到背包问题1.斐波那契数列2.爬楼梯3.零钱转换Python代码 4.零钱兑换 II5.组合数dp和排列数dp6.为什么动态规划的核心思想计算组合数的正确方法代码实现 为什么先遍历…

【C++打怪之路Lv8】-- string类

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…

智能汽车智能网联

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

深入理解线性表--顺序表

目录 顺序表- Seqlist -> sequence 顺序 list 表 顺序表的概念 问题与解答 顺序表的分类 静态顺序表 动态顺序表 问题与解答(递进式) 动态顺序表的实现 尾插 头插 尾删 头删 指定位置插入 指定位置删除 销毁 总结 前言&#xff1a;线性表是具有相同特性的一类数据结构…

【exceljs】纯前端如何实现Excel导出下载和上传解析?

前段时间写过一篇类似的文章&#xff0c;介绍了sheetjs。最近发现了一个更好用的库ExcelJS&#xff0c;它支持高级的样式自定义&#xff0c;并且使用起来也不复杂。实际上sheetjs也支持高级自定义样式&#xff0c;不过需要使用付费版。 下面对比了Exceljs和Sheetjs&#xff1a…

Linux的习题+一道回溯类型的算法题

Linux的习题 Linux环境与版本 1.linux 2.6.* 内核默认支持的文件系统有哪些&#xff1f;[多选] A.ext3 B.ext2 C.ext4 D.xfs E.ufs 正确答案&#xff1a;ABCD A 全称Linux extended file system, extfs,即Linux扩展文件系统&#xff0c;ext2为第二代 D XFS一种高性能的日…

使用频率最高的 opencv 基础绘图操作 - python 实现

以下是 opencv-python 基本操作绘制示例&#xff0c;绘制&#xff1a; 1&#xff09;圆&#xff0c;2&#xff09;矩形&#xff0c;3&#xff09;线段&#xff0c;4&#xff09;文本。 安装 opencv-python pip install opencv-python 在图上绘制圆的操作&#xff0c;示例如…

HCIP-HarmonyOS Application Developer 习题(五)

1、以下哪种原子化布局能力属于自适应变化能力? A. 拉伸 B.占比 C. 隐藏 D.拆行 答案&#xff1a;A 分析&#xff1a;划分为“自适应变化能力”和“自适应布局能力”两类。 其中&#xff0c;自适应变化能力包含了缩放能力和拉伸能力&#xff0c;自适应布局能力包含了隐藏、折…

『Mysql进阶』Mysql explain详解(五)

目录 Explain 介绍 Explain分析示例 explain中的列 1. id 列 2. select_type 列 3. table 列 4. partitions 列 5. type 列 6. possible_keys 列 7. key 列 8. key_len 列 9. ref 列 10. rows 列 11. filtered 列 12. Extra 列 Explain 介绍 EXPLAIN 语句提供有…

Spring学习——SpringAOP

0. IOC思想(DI)1. 关键注解Repositorypublic class DeptDaoImpl1 implements DeptDao{}RepositoryPrimarypublic class DeptDaoImpl2 implements DeptDao{}Servicepublic class DeptServiceImpl implements DeptService{AutowiredQulifier("deptDaoImpl2")private De…

UE5学习笔记24-添加武器弹药

一、给角色的武器添加弹药 1.创建界面&#xff0c;根据笔记23的界面中添加 2.绑定界面控件 UPROPERTY(meta (Bindwidget))UTextBlock* WeaponAmmoAmount;UPROPERTY(meta (Bindwidget))UTextBlock* CarriedAmmoAmount; 3.添加武器类型枚举 3.1创建武器类型枚举头文件 3.2创建文…