运算符重载详解(完全版)

1.运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字和参数列表,其返回值类型与参数列表都与普通的函数类似

函数名:关键字operator后面接需要重载的运算符符号

函数原型返回值类型 operator操作符(参数列表)

注意点

  • 不能通过连接其他符号来创建新的操作符,比如operator@
  • 重载操作符必须有一个类类型参数,比如不可以对整型进行重载
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .*  ::    sizeof  ?:   . 以上5个运算符不能重载 
class Date
{
public:
	//构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//bool operator==(Date* this,const Date& d2)
	//这里需要注意的是,左操作数是this,指向调用函数的对象
	bool operator==(const Date& d2)
	{
		return _year == d2._year
			&& _month == d2._month
			&& _day == d2._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

2.赋值运算符重载

2.1赋值运算符重载格式

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值的目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this:要复合连续赋值的含义  
class Date
{
public:
	//构造函数
	Date(int year = 1900, 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;
	}
	//赋值运算符重载
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

 2.2注意点

1.赋值运算符只能重载成类的成员函数不能重载成全局函数

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

2.用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值

class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}

	Time& operator=(const Time& t)
	{
		if (this != &t)
		{
			_hour = t._hour;
			_minute = t._minute;
			_second = t._second;
		}
		return *this;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
private:
	//内置类型
	int _year = 1970;
	int _month = 1;
	int _day = 1;

	//自定义类型
	Time _t;
};

int main()
{
	Date d1;
	Date d2;
	d1 = d2;
	return 0;
}

3.前置++和后置++重载

  • 前置自增运算符重载通常不接收任何参数,其目的是直接对当前对象进行增加操作,然后返回当前对象的引用。 
  • 后置自增运算符重载接收一个 int 类型的参数(通常不使用这个参数),其目的是先保存当前对象的副本,然后对当前对象进行增加操作,最后返回之前保存的副本。
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//前置++:返回+1之后的结果,注意,this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
	Date& operator++()
	{
		_day += 1;
		return *this;
	}
	//后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
	//后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时先将this保存一份,然后给this+1
	//temp是临时对象,因此只能以值的方式返回,不能返回引用
	Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d;
	Date d1(2024, 6, 25);
	d = d1++;//2024,6,25
	d = ++d1;//2024,6,26
	return 0;
}

4.函数重载与运算符重载

函数重载:让函数名相同,但是参数不同的函数存在

运算符重载:让自定义类型可以用运算符,并且控制运算符的行为,增强可读性

多个同一运算符重载可以构成函数重载

Date operator-(int day);//日期-天数
int operator-(const Date& d);//日期-日期

5.重载流插入和提取运算符

目的:为了实现自定义类型的输入和输出,注意自定义类型本质是内置类型

重载流插入运算符,我们可以尝试将其重载为Date类的成员函数

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

这里其实有两个参数,隐含的Date* this占据了第一个参数的位置

我们习惯调用的方式

cout<<d1;

不能用了,因为cout的类型时ostream,d1的类型是Date,这和函数的参数列表的顺序不一致,不能用。如果我们想调用,只能写成d1<<cout;这不符合我们的习惯。所以说,operator<<想重载为成员函数,可以,但用起来不符合正常逻辑,不建议这样处理,我们一般将其重载为全局函数

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

再进行修改,便可以实现链式输出。链式输出的关键在于重载的操作符返回了一个 ostream 类型的引用,当你重载 << 操作符时,返回类型必须是 ostream 的引用。这意味着当你使用 << 操作符时,表达式可以继续被用在另一个 << 表达式中。

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

同理,重载流提取操作符也是如此

istream& operator>>(istream& in,Date& d)
{
  cout<<"请依次输入年月日:>";
  in>>d._year>>d._month>>d._day;

  return in;
}

6.const成员

const成员函数是一个特殊的成员函数,它通过在函数声明的末尾加上const修饰符来定义。这样的成员函数承诺不会修改调用它的对象的状态,即它不会修改类的非静态成员变量。

格式类型  函数名(参数列表)const

特点

  • 不可修改成员变量:在const成员函数内部,对类的非静态成员变量的修改是不允许的,否则会导致编译错误。
  • 可调用性:如果一个对象被声明为const,那么只有const成员函数才能被调用。这是因为非const成员函数可能会改变对象的状态,这不符合对象的常量性。
  • 提高安全性:使用const成员函数可以增加代码的安全性,因为它提供了明确的保证,即函数不会修改对象的状态。这有助于捕获潜在的bug,并使代码更易于理解和维护

示例:

class  MyClass  {
private:
      int  value;

public:
      MyClass(int  val)  :  value(val)  {}

      //  const成员函数
      int  getValue()  const  {
          return  value;  //  可以读取成员变量
      }

      //  非const成员函数
      void  setValue(int  val)  {
          value  =  val;  //  可以修改成员变量
      }
};

 在这个例子中,getValue是一个const成员函数,它只读取成员变量value而不修改它。相反,setValue是一个非const成员函数,它可以修改成员变量value。

在下一篇文章中,我们将实现日期类来巩固运算符重载的知识

点赞收藏关注是博主不断生产优质好文的动力哦~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记因hive配置文件参数运用不当导致 sqoop MySQL导入数据到hive 失败的案例

sqoop MySQL导入数据到hive报错 ERROR tool.ImportTool: Encountered IOException running import job: java.io.IOException: Hive exited with status 64 报错解释&#xff1a; 这个错误表明Sqoop在尝试导入数据到Hive时遇到了问题&#xff0c;导致Hive进程异常退出。状态码…

Lua网站开发之文件表单上传

这个代码示例演示如何上传文件或图片&#xff0c;获取上传信息及保存文件到本地。 local fw require("fastweb") local request require("fastweb.request") local response require("fastweb.response") local cjson require("cjson&q…

windterm多窗口同时操作多台服务器

在配置k8s等多服务器环境时&#xff0c;我们要对多台服务器进行相同的操作&#xff0c;使用多窗口同步输入实现一次命令多段执行 初始配置&#xff0c;服务器都已连好 分屏窗口&#xff0c;按下altw->alth水平分屏&#xff0c;按下altw->altv,垂直分屏 按下ctrlshiftm,…

SAP消息号 VF028

客户在VF11冲销发票之后&#xff0c;没有生成正式的财务凭证&#xff0c;然后VF02的时候出现如下报错&#xff1a; “自动清算出具发票凭证XXXXXXX&#xff08;被冲销凭证号&#xff09;且不可能取消凭证XXXXXXX&#xff08;冲销凭证号&#xff09; 原因&#xff1a;销售订单2…

小程序下拉刷新,加载更多数据,移动端分页

文章目录 页面结构图WXML页面代码js代码wxss代码总结备注 参考&#xff1a;https://juejin.cn/post/7222855604406796346 页面结构图 一般页面就4个结构&#xff1a;最外滚动层、数据展示层、暂无数据层、没有更多数据层。 如图&#xff1a; WXML页面代码 <scroll-view …

[吃瓜教程]南瓜书第3章对数几率回归

第三章 对数几率回归 3.1 算法原理 对数几率回归&#xff08;Logistic Regression&#xff09;是一种统计方法&#xff0c;主要用于二分类问题。它通过拟合一个对数几率函数&#xff08;logit function&#xff09;&#xff0c;即对数几率&#xff08;log-odds&#xff09;与…

oracle 11g rac创建实例时发现只给一节点创建了实例 二节点没创建的处理方法

由于操作失误没有在二节点创建实例 删除数据库重新dbca建库 [oracleracdg1-1 dbs]$ dbca -silent -deleteDatabase -sourceDB rac11dg1 -sysDBAUserName sys -sysDBAPassword oracle_4U Connecting to database 4% complete 9% complete 14% complete 19% complete 23% …

常见网络攻击威胁分享

今天我来分享一下比较常见的网络攻击形式&#xff0c; ARP 欺骗攻击、CC 攻击和 DDoS 流量攻击是较为常见且危害巨大的攻击方式。 一、ARP欺骗攻击 ARP&#xff08;AddressResolutionProtocol&#xff0c;地址解析协议&#xff09;是用于将IP地址转换为MAC地址的协议。ARP欺骗…

ActiViz集成到WPF中的空域问题

文章目录 一、场景1、WPF控件2、集成ActiViz或者VTK 二、问题1、需求2、空域问题 三、解决方案1、用WindowsFormsHost包裹住ElementHost&#xff0c;然后将WPF的控件放在ElementHost职中&#xff1a;2、用Window或者Popup去悬浮3、使用第三方库Microsoft.DwayneNeed&#xff08…

springcloud-gateway 路由加载流程

问题 Spring Cloud Gateway版本是2.2.9.RELEASE&#xff0c;原本项目中依赖服务自动发现来自动配置路由到微服务的&#xff0c;但是发现将spring.cloud.gateway.discovery.locator.enabledfalse 启动之后Gateway依然会将所有微服务自动注册到路由中&#xff0c;百思不得其解&a…

NineData和华为云在一起!提供一站式智能数据库DevOps平台

以GuassDB数据库为底座 NineData和华为云一起 为企业提供 一站式智能数据库DevOps平台 帮助开发者 高效、安全地完成 数据库SQL审核 访问控制、敏感数据保护等 日常数据库相关开发任务 NineData 智能数据管理平台 NineData 作为新一代的云原生智能数据管理平台&#xf…

Js逆向爬虫基础篇

这里写自定义目录标题 逆向技巧断点一 、请求入口定位1. 关键字搜索2. 请求堆栈3. hook4. JSON.stringify 二、响应入口定位&#xff1a;1. 关键字搜索2. hook3. JSON.parse 逆向技巧 断点 普通断点 条件断点 日志断点 XHR断点 一 、请求入口定位 1. 关键字搜索 key关…

【因果推断python】57_The Difference-in-Differences 3

目录 3) Enlightenment: A Flexible Functional Form Key Concepts 3) Enlightenment: A Flexible Functional Form 有好消息也有坏消息。首先是好消息&#xff1a;我们已经发现问题与函数形式有关&#xff0c;因此我们可以通过修正函数形式来解决这个问题。也就是说&#xf…

竞赛选题 python+大数据校园卡数据分析

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于yolov5的深度学习车牌识别系统实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;3分 该项目较为新颖&am…

短视频最佳时长:成都柏煜文化传媒有限公司

探索时间与内容之间的完美平衡 成都柏煜文化传媒有限公司 在数字媒体日益繁荣的今天&#xff0c;短视频已成为人们获取信息、娱乐休闲的重要形式。然而&#xff0c;关于短视频的最佳时长&#xff0c;一直是一个备受争议的话题。本文将探讨短视频时长的各种考量因素&#xff0…

基于MATLAB对线阵天线进行道尔夫—切比雪夫加权

相控阵天线——基于MATLAB对线阵进行道尔夫—切比雪夫加权 目录 前言 一、阵列天线的综合 二、道尔夫—切比雪夫综合 三、单元间距的改变对切比雪夫阵列方向图的影响 四、单元数的改变对切比雪夫阵列激励分布的影响 五、副瓣电平SLL对切比雪夫阵列激励幅度的影响 六、副…

深入理解Java中的Collectors(Stream流)

引言 在 Java 的 Stream API 中&#xff0c;Collectors 是一个非常强大的工具类&#xff0c;它提供了许多静态方法&#xff0c;用于将 Stream 的元素收集到集合、字符串或其他类型的结果中。使用 Collectors&#xff0c;我们可以轻松地进行数据聚合和转换操作。 文章目录 引言…

小区业主管理系统

摘 要 随着城市化进程的加速和人口的不断增加&#xff0c;小区的数量也在不断增加。小区作为城市居民居住的主要场所&#xff0c;其管理工作也变得越来越重要。传统的小区业主管理方式存在诸多问题&#xff0c;如信息传递不畅、业务处理效率低下等。因此&#xff0c;开发一个高…

Spring底层原理之FactoryBean Bean工厂 单例对象 多例对象

FactoryBean 在 Spring Framework 中&#xff0c;FactoryBean 是一个用于创建其他 Bean 实例的特殊工厂 Bean。它允许开发者自定义 Bean 的创建逻辑&#xff0c;从而更加灵活地管理和配置 Bean 的实例化过程。 FactoryBean 接口 FactoryBean 接口是 Spring 框架中的一个重要…

启动VMWare虚拟机报错

1. 无法打开内核设备“\\.\VMCIDev\VMX”: 操作成功完成。是否在安装 VMware Workstation 后重新引导? 模块“DevicePowerOn”启动失败。 未能启动虚拟机。 解决办法: 解决办法: 将 Ubuntu 64 位.vmx 找到vmci0.present"TRUE"这行改成 vmci0.present "FAL…