C++运算符重载详解(日期类实操)

news2024/11/29 2:39:26

前言:为什么要实现运算符重载?

在C语言中,对于内置类型,我们可以根据符号>、<、==等去直接比较大小,但是对于自定义来说,肯定不能直接比较大小,例如下面的日期类,想要比较两个两个日期的大小,或者相差多少天,直接写运算符肯定是不行的。

class Date
{
private:
	int _year;
	int _month;
	int _day;
};

这时候就需要运算符重载出马了!

运算符重载的概念:

运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类

型与参数列表与普通的函数类似。

函数名字为:

关键字operator后面接需要重载的运算符符号。

函数原型:

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

注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@ 
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

日期类运算符实操

头文件(函数的声明)

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);
	//打印日期
	void Print();

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
  // d2(d1)
	Date(const Date& d);
	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();

	// >运算符重载
	bool operator>(const Date& d);
	// ==运算符重载
	bool operator==(const Date& d);
	// >=运算符重载
	bool operator >= (const Date& d);
	// <运算符重载
	bool operator < (const Date& d);
	// <=运算符重载
	bool operator <= (const Date& d);
	// !=运算符重载
	bool operator != (const Date& d);
	// 日期-日期 返回天数
	int operator-(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

重载实现(函数的定义):

int Date::GetMonthDay(int year, int month)
{
	int arr[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;
	return arr[month];
}

void Date::Print()
{
	cout << _year << '-' << _month << '-' << _day;
}


//构造函数的参数声明给,定义不给
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}


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

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

Date::~Date()
{
	_year = 0;
	_month = 0;
	_day = 0;
}

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

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

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

bool Date::operator>=(const Date& d)
{
	return operator==(d) || operator>(d);
}

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

bool Date::operator != (const Date& d)
{
	return !operator==(d);
}


Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
		}
	}
	return *this;
}

//前置++和后置++的区别就是构成重载,参数加上int
//在调用的时候,有参数会调用前置++,没有参数会调用后置++
Date& Date::operator++()
{
	(*this) += 1;
	return *this;
}

 // 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1
 //       而temp是临时对象,因此只能以值的方式返回,不能返回引用


Date Date::operator++(int)
{
	//调用拷贝构造函数
	Date tmp(*this);
	(*this) += 1;
	return tmp;
}

Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}


int Date::operator-(const Date& d)
{
	int cnt = 0;
	while (*this != d)
	{
		cnt++;
		(*this)--;
	}
	return cnt;
}

Date& Date::operator--()
{
	(*this) -= 1;
	return *this;
}

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

Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp._day += day;
	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	{
		tmp._day -= GetMonthDay(tmp._year, tmp._month);
		tmp._month++;
		if (tmp._month == 13)
		{
			tmp._year++;
		}
	}
	return tmp;
}

重载过程中的注意点:

  • 构造函数如果声明和定义分离,声明需要将参数赋缺省值,定义不需要写,以防混淆。
  • 传参数时尽量都要用引用传参,可以提高传参的效率
  • 传返回值时,如果返回值在调用完这个函数没有被销毁,需要引用返回,如果销毁了,直接返回。
  • 复用已经实现的函数

赋值运算符重载:

1. 赋值运算符重载格式

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义

2、前置++后置++的重载区别


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

this指向的对象函数结束后不会销毁,故以引用方式返回提高效率

输入流输出流操作符重载

为什么cin cout能够自动识别任意类型的数据呢?

本质上就是函数的重载

原码:

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

	return out;
}

istream& operator>>(istream& in, const Date& d)
{
	in >> d._year >> d._month >> d._day;

	return in;
}

总结:

其他的运算符一般是实现成成员函数,<< >>运算符必须是实现到全局,这样才能让流对象做第一个参数,才符合可读性。不然可读性很差,像下面定义在类的内部:

重载流操作符为什么必须用引用?

如果我们使用值传送来传递一个流给函数,那么在函数里要生成一个该流的临时变量,生成临时变量的时候,就要调用对应的拷贝构造函数,并且这个拷贝构造函数必须是以一个值传送的流作为参数的——但是流就是没有这样的拷贝构造函数

分析:

流本质是为了解决,自定义类型的输入和输出问题,printf scanf 无法解决自定义类型的输入输出问题

面向对象 + 运算符重载解决!

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

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

相关文章

Genio 500_MT8385安卓核心板:功能强大且高效

Genio 500(MT8385)安卓核心板是一款功能强大且高效的AIoT平台&#xff0c;内置的AI处理器(APU)工作频率可达500MHz&#xff0c;支持深度学习、神经网络加速和计算机视觉应用。配合高达2500万像素的摄像头&#xff0c;可以为AI相机应用提供清晰、精确的图像&#xff0c;如人脸识…

vscode中Chinese (Simplified)汉化无效解决方法

问题复现 之前已经下载了 Chinese (Simplified)插件并启用了&#xff0c;都是正常的中文简体。有时候打开vscode的时候&#xff0c;会发现汉化失效了&#xff0c;如图&#xff1a; 解决方法 依次点击 扩展&#xff08;Extensions&#xff09;— Chinese (Simplified) — 选…

Banana Pi BPI-W3之RK3588安装Qt+opencv+采集摄像头画面.

场景&#xff1a;在Banana Pi BPI-W3 RK3588上做qt开发工作RK3588安装Qtopencv采集摄像头画面 2. 环境介绍 硬件环境&#xff1a; Banana Pi BPI-W3RK3588开发板、MIPI-CSI摄像头( ArmSoM官方配件 )软件版本&#xff1a; OS&#xff1a;ArmSoM-W3 Debian11 QT&#xff1a;QT5…

LeetCode(20)最长公共前缀【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 14. 最长公共前缀 1.题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow&qu…

【计算机组成原理】定点加法、减法运算

系列文章目录 绘制出纯整数(1字节)和纯小数的数轴 将十进制数20.59375&#xff0c;转换成754标准的32位浮点数的二进制存储格式 用双符号位补码求 x 0.1010011, y -0.1001010, 分别求出 x y, x - y&#xff0c;并判溢出

求10的阶乘之和

这个问题很简单&#xff0c;我们用for循环就可以做到&#xff01; 目录 1.用两个for循环求值 2.用一个for循环求值 1.用两个for循环求值 int main() {int i 1;int ret 1;int sum 0;int n 0;for (n 1; n < 10; n){ret 1;for (i 1; i < n; i){ret ret * i;}sum …

Linux_/proc目录_查看处理器的信息/proc/cpuinfo

1、cat /proc/cpuinfo_查看/proc/cpuinfo文件的内容 可以看到板卡有4个处理器&#xff0c;剩下的信息emmm...... 2、BogoMIPS_反映CPU运算速率 MIPS是millions of instructions per second(百万条指令每秒)的缩写&#xff0c;其代表CPU的运算速率。 BogoMIPS是Linux大致计算…

elementplus DateTimePicker 日期范围选择器 设置默认时间范围为当前月的起始时间到结束时间

代码如下&#xff1a; <el-date-pickerv-model"value"type"datetimerange"start-placeholder"Start Date"end-placeholder"End Date":default-time"defaultTime" />const defaultTime: [Date, Date] [new Date(2000…

el-table中el-popover失效问题

场景&#xff1a;先有一个数据表格&#xff0c;右侧操作栏为固定列&#xff0c;另外有一个字段使用了el-popover来点击弹出框来修改值&#xff0c;发现不好用&#xff0c;点击后无法显示弹出框&#xff0c;但当没有操作栏权限时却意外的生效了。 这种问题真是不常见&#xff0…

蓝桥杯 vector

vector的定义和特性 注意&#xff1a;vector需要开C11标准 vector的常用函数 push_back():将元素添加到vector末尾 pop_back():删除vector末尾的元素 begin()和end():返回指向vector第一个元素和最后一个元素之后一个位置的迭代器。 示例 vector<int> vec{10,20,30};f…

Leetcode刷题详解——衣橱整理

1. 题目链接&#xff1a;LCR 130. 衣橱整理 2. 题目描述&#xff1a; 家居整理师将待整理衣橱划分为 m x n 的二维矩阵 grid&#xff0c;其中 grid[i][j] 代表一个需要整理的格子。整理师自 grid[0][0] 开始 逐行逐列 地整理每个格子。 整理规则为&#xff1a;在整理过程中&am…

【Linux】环境变量--PATH环境变量/环境变量的操作/命令行参数

文章目录 一、PATH环境变量1.什么是PATH环境变量2.如何添加PATH环境变量3.系统中的其他环境变量4.环境变量的来源 二、环境变量的操作1.设置环境变量2.通过getenv获取环境变量3.环境变量的意义 三、命令行参数 一、PATH环境变量 1.什么是PATH环境变量 这里我们先提出一个问题…

限制Domain Admin登录非域控服务器和用户计算机

限制Domain Admin管理员使用敏感管理员帐户(域或林中管理员组、域管理员组和企业管理员组中的成员帐户)登录到信任度较低的服务器和用户端计算机。 此限制可防止管理员通过登录到信任度较低的计算机来无意中增加凭据被盗的风险。 建议采用的策略 建议使用以下策略限制对信任度…

Python 自动化: eip、cen监控数据对接到 grafana

新钛云服已累计为您分享775篇技术干货 概览 日常运维中&#xff0c;我们有时需要关注阿里云中 EIP 和 CEN 的监控数据&#xff0c;如果每次登录到平台查看&#xff0c;不太方便。 可以通过 API 获取监控数据&#xff0c;并输入到 influxDB&#xff0c;然后再到 Grafana 中展示&…

2023最新最全【虚幻4引擎】下载安装零基础教程

1、创建Epic Games账户 我们先打开浏览器&#xff0c;输入以下网址&#xff1a;unrealengine.com 随后点击【立即开始】 选择许可证类型&#xff0c;此处提供三种选项&#xff0c;分别是【游戏】、【非游戏】以及【私人定制】 第一类许可证适用于游戏和商业互动产品&#xff…

CSS特效012:边框线条环绕流动效果

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS…

小程序如何添加打印机来打印订单

在采云小程序中&#xff0c;支持打印订单的小票、标签、发货单和电子面单。小票打印机用于打印小票&#xff0c;类似于超市小票、外卖小票等。标签打印机用于打印商品标签&#xff0c;类似于奶茶上面粘贴的标签&#xff0c;用于表示饮料名称和规格等。货单打印机用于打印发货单…

Rust 语言中的结构体

目录 1、结构体 2、结构体的定义和实例化 2.1 使用字段初始化简写语法 2.2 使用结构体更新语法从其他实例创建实例 2.3 没有命名字段的元组结构体 2.4 没有任何字段的类单元结构体 2.5 结构体示例程序 3、方法 3.1 关联函数 3.2 多个 impl 块 1、结构体 struct&…

C++二分查找算法:规划兼职工作

题目 你打算利用空闲时间来做兼职工作赚些零花钱。 这里有 n 份兼职工作&#xff0c;每份工作预计从 startTime[i] 开始到 endTime[i] 结束&#xff0c;报酬为 profit[i]。 给你一份兼职工作表&#xff0c;包含开始时间 startTime&#xff0c;结束时间 endTime 和预计报酬 pro…

DDR3 的相关设计规范(个人总结)

文章目录 阻抗控制布局布线电源处理时序要求 DDR3 的相关设计规范(个人总结) 阻抗控制 DDR3 要严格控制阻抗&#xff0c;单线 50ohm&#xff0c;差分 100ohm&#xff0c;差分一般为时钟、DQS。在走线过程中&#xff0c;尽量减小阻抗跳变的因素&#xff0c;比如:换层(无法避免…