03C++类与对象之运算符重载

news2024/12/29 23:40:06

文章目录

  • C++类与对象之运算符重载与const成员
    • 运算符重载
    • 赋值运算符重载
      • 运算符重载
    • 日期类的实现与运算符重载
      • 赋值运算符重载
      • 比较类运算符的重载
      • 二元运算符+-的重载
      • 前置++和后置++重载
    • 总体实现代码
    • const成员
      • const的好处
          • 1.防止程序员犯错
          • 2.提高代码的复用性
      • const 成员与函数重载规则

在这里插入图片描述

C++类与对象之运算符重载与const成员

运算符重载

赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this
. :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现*

日期类的实现与运算符重载

像这种运算符重载,我们可以思考多个运算符代码到复用(在这里统一说一下const可以暂时不管,同时此处会涉及到后面的友元类,友元类就是虽然不是成员函数,就是没用this指针,但是可以访问私有成员数据)

基本实现

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);

	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;

public:
    Date(){}
	Date(int year, int month, int day);

	int  Get_day()
	{
		return _day;
	}
    
	int Get_month()
	{
		return _month;
	}
    
	int Get_year()
	{
		return _year;
	}
    
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
    
	int Getmonthday(int year,int month)
	{
		static int monthday[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31};
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			return 29;
		}
		else
		{
			return monthday[month];
		}
	}
	
	Date(const Date& B)
	{
		
		_day = B._day;
		_month = B._month;
		_year = B._year;
	}
    
    bool operator<(const Date& x) const;
	bool operator==(const Date& x) const;
	bool operator<=(const Date& x) const;
	bool operator>(const Date& x) const;
	bool operator>=(const Date& x) const;
	bool operator!=(const Date& x) const;
	Date& operator+=(int day);
	Date operator+(int day) const;

	Date& operator-=(int day);
	Date operator-(int day) const;
	int operator-(const Date& d) const;
	Date& operator=(const Date& d)  
	{
		if (!(this == &d))
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
    Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}

	Date& operator++()
	{
		_day += 1;
		return *this;
	}
	Date& operator--()
	{
		_day -= 1;
		return *this;
	}
	Date operator--(int)
	{
		Date temp = *this;
		_day -= 1;
		return temp;
	}

赋值运算符重载

  • 参数类型:const T&,传递引用可以提高传参效率(因为无需调用赋值构造函数)

  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

    	Date A(2023,5,4);
    	Date B(A);//赋值构造
    	Date C;
    	Date D;
    	C = D = B;//B赋值给D,同时D的赋值函数返回D的引用,将D赋给C
    
  • 检测是否自己给自己赋值

  • 返回*this :要复合连续赋值的含义

Date& operator=(const Date& d)
	{
		if (!(this == &d))
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

比较类运算符的重载

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 代码复用:可以先重载<和==,其他的复用其代码就行
  • 返回bool:即判断是否正确
bool Date::operator<(const Date& x) const
{
	if (_year < x._year)
	{
		return true;
	}
	else if (_year == x._year && _month < x._month)
	{
		return true;
	}
	else if (_year == x._year && _month == x._month && _day < x._day)
	{
		return true;
	}

	return false;
}
bool Date::operator==(const Date& x) const
{
	return _year == x._year
		&& _month == x._month
		&& _day == x._day;
}

bool Date::operator<=(const Date& x) const
{
	return *this < x || *this == x;
}

bool Date::operator>(const Date& x) const
{
	return !(*this <= x);
}

bool Date::operator>=(const Date& x) const
{
	return !(*this < x);
}

bool Date::operator!=(const Date& x) const
{
	return !(*this == x);
}

二元运算符±的重载

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}

	_day += day;
	while (_day > Getmonthday(_year, _month))
	{
		_day -= Getmonthday(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day)  const
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}

	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}

		_day += Getmonthday(_year, _month);
	}

	return *this;
}

Date Date::operator-(int day) const//日期加天数,算多少天前的日期
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

int Date::operator-(const Date& d) const//日期减日期,算相差的天数
{
	Date max = *this;
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

前置++和后置++重载

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1

	Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}

	Date& operator++()
	{
		_day += 1;
		return *this;
	}

同理,前置–和后置–

	Date& operator--()
	{
		_day -= 1;
		return *this;
	}
	Date operator--(int)
	{
		Date temp = *this;
		_day -= 1;
		return temp;
	}

总体实现代码

#include"date.h"

Date::Date(int year, int month, int day)
{
	if (month > 0 && month < 13
		&& day > 0 && day <= Getmonthday(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
}

bool Date::operator<(const Date& x) const
{
	if (_year < x._year)
	{
		return true;
	}
	else if (_year == x._year && _month < x._month)
	{
		return true;
	}
	else if (_year == x._year && _month == x._month && _day < x._day)
	{
		return true;
	}

	return false;
}
bool Date::operator==(const Date& x) const
{
	return _year == x._year
		&& _month == x._month
		&& _day == x._day;
}

bool Date::operator<=(const Date& x) const
{
	return *this < x || *this == x;
}

bool Date::operator>(const Date& x) const
{
	return !(*this <= x);
}

bool Date::operator>=(const Date& x) const
{
	return !(*this < x);
}

bool Date::operator!=(const Date& x) const
{
	return !(*this == x);
}

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}

	_day += day;
	while (_day > Getmonthday(_year, _month))
	{
		_day -= Getmonthday(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day)  const
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}

	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}

		_day += Getmonthday(_year, _month);
	}

	return *this;
}

Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

ostream& operator<<(ostream& out,const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
istream& operator>>(istream& in,Date& d)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.Getmonthday(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
	return in;
}

const成员

const的好处

1.防止程序员犯错

就拿上面的日期减天数的代码来说

这个代码不能改变原来的日期类,只有-=才改变。如果你没有加const,你可能在写代码时犯错,不小心把原来的日期类改了

Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}
2.提高代码的复用性

如果-的重载没有加const

Date Date::operator-(int day) 
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

我们运行这个代码

const Date d1(2023,5,1);
	Date d2 = d1 - 100;3

在这里插入图片描述

原因在于d1是 const Date类,不能改变,所以他的取地址应该是const Data*this,而系统传过去的this指针是一个普通的,这属于权限放大了(具体可以看看我前面的&(引号)的使用),而又因为this不能自己改C++添加了个在函数后面的const 的方法给this指针添加const

那么我们的const的对象就可以调用-这个函数了

const 成员与函数重载规则

能不能构成重载得看是单纯传值还是是否涉及到权限问题,比如形参是const 引用和指针,这就涉及到了权限所以能重载,而类的成员函数有this指针,也能构成,如果是传值的话,没有涉及到权限所以不构成,但以下图片中的text函数未构成函数重载的原因是const 为管控到this指针,所以未涉及到权限问题,未构成函数重载(记住只是单纯的赋值重载不行,其他都可以)

再者调用关系上,如果两个函数都实现了,那么const 类型的调const的,普通的调普通的,但如果只有const函数,那么普通的类型也可以调const类型的函数

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

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

相关文章

Qt文件系统源码分析—第三篇QDir

深度 本文主要分析Windows平台&#xff0c;Mac、Linux暂不涉及 本文只分析到Win32 API/Windows Com组件/STL库函数层次&#xff0c;再下层代码不做探究 本文QT版本5.15.2 类关系图 QTemporaryFile继承QFile QFile、QSaveFile继承QFileDevice QFileDevice继承QIODevice Q…

由浅入深Netty基础知识IO相关

目录 1 stream vs channel2 IO 模型3 零拷贝3.1 传统 IO 问题3.2 NIO 优化 4 AIO4.1 文件 AIO4.2 守护线程4.3 网络 AIO 1 stream vs channel stream 不会自动缓冲数据&#xff0c;channel 会利用系统提供的发送缓冲区、接收缓冲区&#xff08;更为底层&#xff09;stream 仅支…

unity学习遇到的问题:解决VS不能加载Unity脚本,MonoBehaviour是灰色的

电脑出了点问题&#xff0c;然后就重装了&#xff0c;重装之后&#xff0c;从gitee上下载了原来的半截代码&#xff0c;结果发现里面的脚本运行出问题了&#xff0c;仔细一看&#xff0c;MonoBehaviour是灰色的&#xff0c;也就是说&#xff0c;加载不了unity的api了&#xff0…

目标检测复盘 --3. RCNN

RCNN的CNN部分使用AlexNet作为backbone来提取特征&#xff0c;Fast RCNN使用了VGG16来作为backboneRCNN将2000个框送入网络提取特征&#xff0c;Fast RCNN是将图像送入CNN来提取特征得到一个特征图将SS(Selective Search)算法获取的提议框映射到上面的特征图上&#xff0c;获取…

怎么通过ssh连上ipv6的服务器?阿里云怎么配置ipv6?wsl2怎么支持ipv6?

最近在研究ipv6&#xff0c;光调通环境居然让我折腾了好多回&#xff0c;现在终于通了 在这里提一句&#xff0c;IPV6和IPV4是两种东西&#xff0c;不要想着ipv6兼容ipv4&#xff0c;你就当它是全新的东西 1.前置条件 1.1我的电脑能访问ipv6 测试通过就代表你电脑可以访问ip…

Redis 哨兵模式的实现详解

文章目录 高可用&#xff08;HA&#xff09;哨兵模式概述哨兵的搭建伪集群 哨兵1. 复制sentinel.conf文件2. 修改sentinel.conf文件3. 新建sentinel26380.conf4. 启动并关联Redis集群5. 启动Sentinel集群6. 查看 Sentinel 信息7. 查看 Sentinel 配置文件 哨兵优化配置 高可用&…

【腾讯云Finops Crane集训营】降本增效神器Crane实战记录

本章目录 前言一、Crane是什么&#xff1f;Crane的主要功能&#xff1f;FinOps 是什么Prometheus是什么Grafana是什么 二、不得不面对的问题&#xff1a;云上资源效能挑战&#xff01;三、云原生场景下的成本优化挑战&#xff1f;四、K8s原生能力的不足五、Crane智能调度助力成…

Linux命令之vim/vi

目录 vim/vi简介 vi/vim 的使用 操作实例 总结 vim/vi简介 所有的 Unix Like 系统都会内建 vi 文书编辑器&#xff0c;其他的文书编辑器则不一定会存在。但是目前我们使用比较多的是 vim 编辑器。Vim 是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程…

i.MX6ULL - 远程视频监控方案实现(nginx-rtmp流媒体服务器、ffmpeg推流)

i.MX6ULL - 远程视频监控配置&#xff08;nginx-rtmp流媒体服务器、ffmpeg推流&#xff09; 目录 i.MX6ULL - 远程视频监控配置&#xff08;nginx-rtmp流媒体服务器、ffmpeg推流&#xff09;1、前言2、buildroot文件系统构建2.1 勾选alsa-utils&#xff08;选做&#xff1a;如果…

桥接模式与NAT模式的区别以及设置静态IP

概述 日常我们都会使用到虚拟机&#xff0c;本文章以VMware虚拟机为例&#xff0c;主要介绍下虚拟机设置桥接模式与NAT模式的区别&#xff0c;并通过示意图进行讲解。并且会介绍如何去设置静态IP。 模式介绍 NAT模式NAT模式下 &#xff0c;创建出来的虚拟机只能访问当前主机…

基于ensp的跨地区的校园网组网方案

本博客是基于模拟器ensp的校园网组网方案&#xff0c;有总校区和分校区&#xff0c;主要用了vlan划分、dhcp、nat、ospf、acl、bgp等技术。首先说一下本博客的局限性&#xff1a; 总校区和分校区之间只是使用的传统的bgp建立连接&#xff0c;这样可以在运营商上看到内网的明细&…

HTTP1.1(七)内容协商和资源表述

一 内容协商和资源表述 ① 铺垫 1) 由于一种资源对应许多种状态,所以客户端接收资源表述的转移时需要进行协商比如&#xff1a;[1]、一个来自中国的用户他的浏览器访问一个页面时得到中文页面[2]、一个其它国家的用户访问同一个页面时得到的是他本国的页面补充&#xff1a;…

在线协作助力团队合作:解析多种高效工具实现团队协同

在线协作是通过网络为平台&#xff0c;将团队成员连接起来&#xff0c;使其共同创作、共享讯息&#xff0c;进行团队合作。这种协作方式突破了线下的空间限制性&#xff0c;使团队合作更加及时便捷。因此&#xff0c;越来越多的团队选择了在线协作。 在线协作为团队带来了什么帮…

IDEA 2019.1 与 apache-maven-3.6.3 版本不兼容解决办法

-------IDEA 2019.1 与 apache-maven-3.6.3 版本不兼容 解决办法&#xff1a;降低 Maven版本为 3.3 到底得踩过多少坑&#xff0c;才能让你不再流泪&#xff0c;

接初识HTML中的基础知识,简单明了!!!

续——HTML的基础知识&#xff01;&#xff01;&#xff01; 一、表格 关于HTML中用table表示一个表格&#xff0c;用tr来表示一行&#xff0c;用td来表示一列。 Demo&#xff1a;表示一个二行三列的表格 <!--根--> <html><!--头--> <head><…

瑞吉外卖 - 文件上传与下载功能(15)

某马瑞吉外卖单体架构项目完整开发文档&#xff0c;基于 Spring Boot 2.7.11 JDK 11。预计 5 月 20 日前更新完成&#xff0c;有需要的胖友记得一键三连&#xff0c;关注主页 “瑞吉外卖” 专栏获取最新文章。 相关资料&#xff1a;https://pan.baidu.com/s/1rO1Vytcp67mcw-PD…

pandas dataframe 中 explode()函数用法及效果

最近在使用pyspark处理数据&#xff0c;需要连接各种各样的表和字段&#xff0c;因此记录相关函数的使用情况。今天介绍explode(). 1. explode()函数简介 explode 函数是 pandas.DataFrame 类的一个方法&#xff0c;能够通过pyspark间接调用。 它可以将一个包含list或者其它可…

【零基础学JS - 7 】javaScript 中的8大数据类型

&#x1f468;‍&#x1f4bb; 作者简介&#xff1a;程序员半夏 , 一名全栈程序员&#xff0c;擅长使用各种编程语言和框架&#xff0c;如JavaScript、React、Node.js、Java、Python、Django、MySQL等.专注于大前端与后端的硬核干货分享,同时是一个随缘更新的UP主. 你可以在各个…

Python之selenium关于Chrome驱动位置,闪退的问题和安装路径

目录 零、查看Python的安装路径一、Chromedriver放置的位置二、浏览器闪退 零、查看Python的安装路径 一、Chromedriver放置的位置 背景&#xff1a;之前由于Chrome浏览器自动升级后&#xff0c;导致驱动与浏览器不匹配&#xff0c;自己也不知道问题出在哪儿&#xff0c;花费了…

hadoop和spark配置问题记录

hadoop和spark配置问题记录 Spark的WebUI访问不了 直接启动的start-all.sh是环境变量中配置的hadoop的脚本&#xff0c;不是spark的&#xff0c;因此启动spark的start-all.sh脚本即可。 Spark看不到Worker信息 启动Spark在UI界面上看不到worker节点的信息_潇洒哥WH3的博客-C…