[C++] 自定义的类如何使用“cout“和“cin“?(含日期类实现)

news2024/11/28 10:43:23

一、引言

在C++中,“cin”和"cout"可以说是区别于C语言的一大亮点。

但是,它的自动识别类型,其本质不过是运算符重载。若真到了能够“自动识别”的那一天,人类大概也能进入新的纪元了罢。

对于我们自己写的类,想要用cout,cin,当然是可以的,我们只需自己写它的重载即可。

本文将以“cout”为例。

二、运算符重载

1、何为运算符重载 

运算符重载:

函数名: operator操作符
返回类型: 看操作符运算后返回值是什么
参数:操作符有几个操作数,它就有几个参数 

其中,有5 个符号是不能进行运算符重载的:::      sizeof         ?:      .      .* 

2、日期类

下面我们以日期类为例,熟悉运算符重载:

众所周知,如果直接在类中进行运算符重载,那么第一个操作数必定是隐含的this指针。

这样就会产生一个问题:本应是“cout<<d”,如今却要写成“d<<cout”

void Test3()
{
	Date d1(2023, 8, 9);
	Date d2(2023, 12, 20);
	Date d3(2003, 12, 1);

	d1 << cout;
	d2 << cout;
	d3 << cout;
}

int main()
{
	Test3();

	return 0;
}

 

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

public:

	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
		{
			days[2] = 29;
		}
		return days[month];
	}

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;

		if (month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month))
		{
			cout << "非法日期" << endl;
		}
	}

	// 拷贝构造函数
    // d2(d1)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;

		return *this;
	}

	// 析构函数
	~Date()
	{
		;
	}

	//打印
	void Print() const
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}

	// 日期+=天数
	Date& operator+=(int day)
	{
		if (day < 0)
		{
			*this -= (-day);
			return *this;
		}
		_day += day;

		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;

			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}

		return *this;
	}

	// 日期+天数
	Date operator+(int day)
	{
		Date tmp = *this;
		tmp += day;
		return tmp;
	}

	// 日期-天数
	Date operator-(int day)
	{
		Date tmp = *this;
		tmp -= day;
		return tmp;
	}

	// 日期-=天数
	Date& operator-=(int day)
	{
		if (day < 0)
		{
			*this += (-day);
			return *this;
		}
		_day -= day;

		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);

		}

		return *this;
	}

	// 前置++
	Date& operator++()
	{
		*this += 1;
		return *this;
	}

	// 后置++
	Date operator++(int)
	{
		Date tmp = *this;
		*this += 1;
		return tmp;
	}

	// 后置--
	Date operator--(int)
	{
		Date tmp = *this;
		*this -= 1;
		return tmp;
	}

	// 前置--
	Date& operator--()
	{
		*this -= 1;
		return *this;
	}

	// >运算符重载
	bool operator>(const Date& d)
	{
		if (_year > d._year)
		{
			return true;
		}
		else if(_year == d._year)
		{
			if (_month > d._month)
			{
				return true;
			}
			else if (_month == d._month)
			{
				if (_day > d._day)
				{
					return true;
				}
			}
		}

		return false;
	}

	// ==运算符重载
	bool operator==(const Date& d)
	{
		return _year == d._year && _month == d._month && _day == d._day;
	}

	// >=运算符重载
	bool operator >= (const Date& d)
	{
		return *this > d || *this == d;
	}

	// <运算符重载
	bool operator < (const Date& d)
	{
		return !(*this >= d);
	}

	// <=运算符重载
	bool operator <= (const Date& d)
	{
		return !(*this > d);
	}

	// !=运算符重载
	bool operator != (const Date& d)
	{
		return !(*this == d);
	}

	// 日期-日期 返回天数
	int operator-(const Date& d)
	{
		int num = 0;
		Date max = *this;
		Date min = d;
		int flag = 1;
		if (*this < d)
		{
			flag = -1;
			max = d;
			min = *this;
		}

		while (max > min)
		{
			num++;
			min++;
		}

		return flag * num;
	}

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

private:

	int _year;
	int _month;
	int _day;

};

3、“cout<<d”

要想使得代码是“cout<<d”而非“d<<cout”,

其实也很简单。我们将<<的重载写在类的外面,就没有了“隐含的this指针”的限制。

但是这样又会产生一个问题:如何访问Date类的私有成员呢?

这时,我们可以利用“友元”来解决问题。

#include<iostream>
using namespace std;



class Date
{
//设置友元
	friend void operator<< (ostream& out, const Date& d);

public:

	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
		{
			days[2] = 29;
		}
		return days[month];
	}

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;

		if (month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month))
		{
			cout << "非法日期" << endl;
		}
	}

	// 拷贝构造函数
    // d2(d1)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;

		return *this;
	}

	// 析构函数
	~Date()
	{
		;
	}

	//打印
	void Print() const
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}

	// 日期+=天数
	Date& operator+=(int day)
	{
		if (day < 0)
		{
			*this -= (-day);
			return *this;
		}
		_day += day;

		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;

			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}

		return *this;
	}

	// 日期+天数
	Date operator+(int day)
	{
		Date tmp = *this;
		tmp += day;
		return tmp;
	}

	// 日期-天数
	Date operator-(int day)
	{
		Date tmp = *this;
		tmp -= day;
		return tmp;
	}

	// 日期-=天数
	Date& operator-=(int day)
	{
		if (day < 0)
		{
			*this += (-day);
			return *this;
		}
		_day -= day;

		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);

		}

		return *this;
	}

	// 前置++
	Date& operator++()
	{
		*this += 1;
		return *this;
	}

	// 后置++
	Date operator++(int)
	{
		Date tmp = *this;
		*this += 1;
		return tmp;
	}

	// 后置--
	Date operator--(int)
	{
		Date tmp = *this;
		*this -= 1;
		return tmp;
	}

	// 前置--
	Date& operator--()
	{
		*this -= 1;
		return *this;
	}

	// >运算符重载
	bool operator>(const Date& d)
	{
		if (_year > d._year)
		{
			return true;
		}
		else if(_year == d._year)
		{
			if (_month > d._month)
			{
				return true;
			}
			else if (_month == d._month)
			{
				if (_day > d._day)
				{
					return true;
				}
			}
		}

		return false;
	}

	// ==运算符重载
	bool operator==(const Date& d)
	{
		return _year == d._year && _month == d._month && _day == d._day;
	}

	// >=运算符重载
	bool operator >= (const Date& d)
	{
		return *this > d || *this == d;
	}

	// <运算符重载
	bool operator < (const Date& d)
	{
		return !(*this >= d);
	}

	// <=运算符重载
	bool operator <= (const Date& d)
	{
		return !(*this > d);
	}

	// !=运算符重载
	bool operator != (const Date& d)
	{
		return !(*this == d);
	}

	// 日期-日期 返回天数
	int operator-(const Date& d)
	{
		int num = 0;
		Date max = *this;
		Date min = d;
		int flag = 1;
		if (*this < d)
		{
			flag = -1;
			max = d;
			min = *this;
		}

		while (max > min)
		{
			num++;
			min++;
		}

		return flag * num;
	}


private:

	int _year;
	int _month;
	int _day;

};

//运算符重载
void operator<< (ostream& cout, const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

效果 

void Test3()
{
	Date d1(2023, 8, 9);
	Date d2(2023, 12, 20);
	Date d3(2003, 12, 1);

	cout << d1;
	cout << d2;
	cout << d3;

}

int main()
{
	Test3();

	return 0;
}

 

如此,我们就实现了将自定义的类使用cout输出了。 

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

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

相关文章

uni-app之app上传pdf类型文件

通过阅读官方文档发现&#xff0c;uni.chooseFile在app端不支持非媒体文件上传&#xff1b; 可以使用这个插件&#xff0c;验证过可以上传pdf&#xff1b;具体使用可以去看文档 插件地址 就是还是会出现相机&#xff0c;这个可能需要自己解决下 实现功能&#xff1a;上传只能上…

vscode ssh远程的config/配置文件无法保存解决

问题 之前已经有了一个config&#xff0c;我想更改连接的地址和用户名&#xff0c;但是无法保存&#xff0c;显示需要管理员权限&#xff0c;但以管理员启动vscode或者以管理员权限保存都不行 未能保存“config”: Command failed: “D:\vscode\Microsoft VS Code\bin\code.c…

ssm+vue基于java的少儿编程网上报名系统源码和论文PPT

ssmvue基于java的少儿编程网上报名系统源码和论文PPT006 开发工具&#xff1a;idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具&#xff1a;navcat,小海豚等 开发技术&#xff1a;java ssm tomcat8.5 摘 要 在国家重视教育影响下&#xff0c;教育部门的密确配合下&#…

如何将Linux上的cpolar内网穿透设置成 - > 开机自启动

如何将Linux上的cpolar内网穿透设置成 - > 开机自启动 文章目录 如何将Linux上的cpolar内网穿透设置成 - > 开机自启动前言一、进入命令行模式二、输入token码三、输入内网穿透命令 前言 我们将cpolar安装到了Ubuntu系统上&#xff0c;并通过web-UI界面对cpolar的功能有…

[YAPI]导出API文档

1.登录点击进去,点击项目2.点击接口,点击编辑,划到最下面,开启开放接口3.点击数据管理, 选择你要的数据导出格式,点击公开接口, 导出完别忘记关闭,防止别人导的时候将你开启的 也一并下载下来

API 测试 | 了解 API 接口概念|电商平台 API 接口测试指南

什么是 API&#xff1f; API 是一个缩写&#xff0c;它代表了一个 pplication P AGC 软件覆盖整个房间。API 是用于构建软件应用程序的一组例程&#xff0c;协议和工具。API 指定一个软件程序应如何与其他软件程序进行交互。 例行程序&#xff1a;执行特定任务的程序。例程也称…

springboot教务综合管理系统java学生教师班级课题jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 springboot教务综合管理系统 系统有1权限&#xff1a…

全球外贸b2b2c跨境电商购物网站开源搭建

要搭建一个全球外贸B2B2C跨境电商购物网站&#xff0c;需要采取以下步骤&#xff08;以下步骤不分先后&#xff09;&#xff1a; 设计系统架构首先需要设计系统的整体架构&#xff0c;确定系统的技术选型、功能模块和业务流程等。可以考虑使用分布式架构&#xff0c;将系统划分…

恒盛策略:沪指冲高回落跌0.26%,酿酒、汽车等板块走弱,燃气股拉升

10日早盘&#xff0c;两市股指盘中冲高回落&#xff0c;半日成交约4200亿元&#xff0c;北向资金净卖出超20亿元。 到午间收盘&#xff0c;沪指跌0.26%报3235.9点&#xff0c;深成指跌0.54%&#xff0c;创业板指跌0.28%&#xff1b;两市算计成交4202亿元&#xff0c;北向资金净…

RocketMQ 延迟消息

RocketMQ 延迟消息 RocketMQ 消费者启动流程 什么是延迟消息 RocketMQ 延迟消息是指&#xff0c;生产者发送消息给消费者消息&#xff0c;消费者需要等待一段时间后才能消费到。 使用场景 用户下单之后&#xff0c;15分钟未支付&#xff0c;对支付账单进行提醒或者关单处理…

C++中的typeid

2023年8月10日&#xff0c;周四下午 目录 概述typeid的用法用法1用法2用法3举例说明 概述 typeid是 C 中的运算符&#xff0c;用于获取表达式或类型的运行时类型信息。 它返回一个std::type_info对象&#xff0c;该对象包含有关类型的信息&#xff0c;例如类型的名称。 type…

怎样学会单片机

0、学单片机首先要明白&#xff0c;一个单片机啥也干不了&#xff0c;学单片机的目的是学习怎么用单片机驱动外部设备&#xff0c;比如数码管&#xff0c;电机&#xff0c;液晶屏等&#xff0c;这个需要外围电路的配合&#xff0c;所以学习单片机在这个层面上可以等同为学习单片…

南大实验pa0:安装环境

安装untubu没问题&#xff0c;但是切到清华软件园之后&#xff0c;问题百出。记录一下 问题1 如上图所示&#xff0c;在安装build-essential的时候出现了问题 The following packages have unmet dependencies:g-11 : Depends: gcc-11-base ( 11.2.0-19ubuntu1) but 11.4.0-1…

杭州企业可以用DV https证书吗

DV https证书是入门级的https证书&#xff0c;也可以叫DV基础型https证书&#xff0c;这款https证书企业是可以用的&#xff0c;甚至商城网站、金融网站都可以使用&#xff0c;不限制申请者&#xff0c;个人或者企事业单位都可以申请。DV基础型https证书虽然只是入门级的https证…

OpenHarmony携千行百业创新成果亮相HDC.Together 2023

8月4日-6日&#xff0c;华为开发者大会2023&#xff08;以下简称“大会”&#xff09;在中国松山湖举办&#xff0c;OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;隆重参会&#xff0c;在大会互动体验区设置了“行业创新展区”&#xff0c;成为大会展区中的…

Debian10:安装PHPVirtualBox

PHPVirtualBox 是一个用 PHP 编写&#xff0c;用于管理 VirtualBox 的 Web 前端&#xff08;由AJAX实现&#xff09;。 参考文章&#xff1a;VirtualBoxPHPVirtualBox部署_骡子先生的博客-CSDN博客php virualbox,浏览器远程控制VBox 虚拟机phpVirtualBox_weixin_39815879的博客…

ctypes使用浅谈

什么是ctypes&#xff1a; ctypes 是 Python 的一个标准库&#xff0c;用于与 C 语言进行交互。它提供了一组工具和函数&#xff0c;可以方便地调用动态链接库&#xff08;DLL&#xff09;或共享对象&#xff08;SO&#xff09;中的 C 函数&#xff0c;并处理 C 数据类型的转换…

探索自动化网页交互的魔力:学习 Selenium 之旅【超详细】

"在当今数字化的世界中&#xff0c;网页自动化已经成为了不可或缺的技能。想象一下&#xff0c;您可以通过编写代码&#xff0c;让浏览器自动执行各种操作&#xff0c;从点击按钮到填写表单&#xff0c;从网页抓取数据到进行自动化测试。学习 Selenium&#xff0c;这一功能…

用普通用户sudo执行ansibe命令

1、编辑/etc/ansible/ansible.cfg 2、hosts文件 3、执行命令 必须加-b选项

无涯教程-Perl - goto函数

描述 该函数具有三种形式,第一种形式使当前执行点跳到称为LABEL的点。这种形式的goto不能用于跳入循环或外部函数。您只能跳至同一范围内的一点。 第二种形式期望EXPR判断为可识别的LABEL。通常,您应该能够使用普通的条件语句或函数来控制程序的执行,因此不建议使用该程序。 …