C++从入门到起飞之——const成员函数Date类实现 全方位剖析!

news2024/11/14 20:22:04

🌈个人主页:秋风起,再归来~
🔥系列专栏:C++从入门到起飞          
🔖克心守己,律己则安

代码链接:这篇文章代码的所有代码都在我的gitee仓库里面啦,需要的小伙伴点击自取哦~

目录

1、const成员函数

2、取地址运算符重载

3、日期类的实现 

3.1Date.h

3.2Date.cpp

0、检查日期是否有效

1、获取某年某月的天数 

 2、全缺省的构造函数

3、拷贝构造函数 

 4、赋值运算符重载 

   5、析构函数

 6、日期+=天数

7、日期+天数

8、日期-天数 

 9、日期-=天数

 10、前置++ 

 11、后置++

12、 后置--

13、 前置--

14、>运算符重载 

15、==运算符重载 

16、 >=运算符重载 

 17、<运算符重载

18、<=运算符重载 

19、!=运算符重载 

20、日期-日期 返回天数 

21、流插入函数重载 

22、流提取函数重载 

3.3Test.cpp

4.完结散花


1、const成员函数

• 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后 ⾯

• const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。 const修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 const Date* const this

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// void Print(const Date* const this) const
	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	// 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩
	Date d1(2024, 7, 5);
	d1.Print();
	const Date d2(2024, 8, 5);
	d2.Print();
	return 0;
}

2、取地址运算符重载

取地址运算符重载分为普通取地址运算符重载const取地址运算符重载。

class Date
{
public:
	Date* operator&()
	{
		return this;
		// return nullptr;
	}
	const Date* operator&()const
	{
		return this;
		// return nullptr;
	}
private:
	int _year; // 年
	int _month; // ⽉
	int _day; // ⽇
};

⼀般这两个函数编译器⾃动 ⽣成的就可以够我们⽤了,不需要去显⽰实现。除⾮⼀些很特殊的场景,⽐如我们不想让别⼈取到当 前类对象的地址,就可以⾃⼰实现⼀份,胡乱返回⼀个地址。

class Date
{
public:
	Date* operator&()
	{
		return (Date*)0x11223344;
		// return nullptr;
	}
	const Date* operator&()const
	{
		return (Date*)0x11223344;
		// return nullptr;
	}
private:
	int _year; // 年
	int _month; // ⽉
	int _day; // ⽇
};

int main()
{
	Date d1, d2;
	cout << &d1 <<endl<< &d2 << endl;
	return 0;
}

 俩个对象的地址都是胡乱返回的(真的损!)

3、日期类的实现 

3.1Date.h

为了便于代码的可读性,我们在日期类中将我们目前需要的成员函数进行声明和定义分离

下面我们先在日期类(Date.h)中声明了我们要完成的一些功能(成员函数)

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
public:

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	// 0、检查日期是否有效
	bool CheckDate();

	// 1、获取某年某月的天数
	int GetMonthDay(int year, int month);

	// 2、全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);

	// 3、拷贝构造函数
	Date(const Date& d);

	// 4、赋值运算符重载
	Date& operator=(const Date& d);

	// 5、析构函数
	~Date();

	// 6、日期+=天数
	Date& operator+=(int day);

	// 7、日期+天数
	Date operator+(int day)const;

	// 8、日期-天数
	Date operator-(int day)const;

	// 9、日期-=天数
	Date& operator-=(int day);

	// 10、前置++
	Date& operator++();

	// 11、后置++
	Date operator++(int);

	// 12、后置--
	Date operator--(int);

	// 13、前置--
	Date& operator--();

	// 14、>运算符重载
	bool operator>(const Date& d)const;

	// 15、==运算符重载
	bool operator==(const Date& d)const;

	//16、 >=运算符重载
	bool operator >= (const Date& d)const;

	// 17、<运算符重载
	bool operator < (const Date& d)const;

	// 18、<=运算符重载
	bool operator <= (const Date& d)const;

	// 19、!=运算符重载
	bool operator != (const Date& d)const;

	// 20、日期-日期 返回天数
	int operator-(const Date& d)const;

	// 21、流插入函数重载
	friend ostream& operator<<(ostream& out, const Date& d);

	// 22、流提取函数重载
	friend istream& operator>>(istream& in, Date& d);

private:
	int _year;
	int _month;
	int _day;
};

3.2Date.cpp

好啦!接下来我们就在Date.cpp这个文件中定义我们要实现的全部成员函数!

0、检查日期是否有效

// 0、检查日期是否有效
bool Date::CheckDate()
{
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

1、获取某年某月的天数 

// 1、获取某年某月的天数
// 因为会被多次调用,所以直接在类里面定义(默认是inline)
int GetMonthDay(int year, int month)
{
	assert(month > 0 && month < 13);
	static int monthDayArray[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 monthDayArray[month];
	}
}

因为会被多次调用,所以直接在类里面定义(默认是inline),这样我们就可以避免频繁的调用该函数建立栈帧,从而提高性能!

 2、全缺省的构造函数

这里需要注意在声明中写了缺省值后,定义时不能再写缺省值!

// 2、全缺省的构造函数
Date::Date(int year , int month , int day )
{
	_year = year;
	_month = month;
	_day = day;
	if (!CheckDate())
	{
		cout << "非法日期:";
		Print();
	}
}

3、拷贝构造函数 

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

 4、赋值运算符重载 

// 4、赋值运算符重载
Date& Date::operator=(const Date& d)
{
	if (this != &d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}

   5、析构函数

Date类其实没有必要显示自定义析构函数!

// 5、析构函数
Date::~Date()
{
	//cout << "~Date()" << endl;
}

 6、日期+=天数

// 6、日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year,_month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}

7、日期+天数

这里复用了+=的代码!

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

8、日期-天数 

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

 9、日期-=天数

// 9、日期-=天数
Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day < 0)
	{
		_month--;
		_day += GetMonthDay(_year, _month);
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}
	}
	return *this;
}

 10、前置++ 

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

 11、后置++

为了区别前置++和后置++,C++规定后置++多一个参数(int)以示区分!

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

12、 后置--

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

13、 前置--

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

14、>运算符重载 

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

15、==运算符重载 

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

16、 >=运算符重载 

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

 17、<运算符重载

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

18、<=运算符重载 

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

19、!=运算符重载 

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

20、日期-日期 返回天数 

// 20、日期-日期 返回天数
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;
}

21、流插入函数重载 

// 21、流插入函数重载
ostream& operator<<(ostream& out,const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

为什么这个函数不定义为成员函数,反而要在全局中定义呢?

其实我们也是可以在类里面声明定义的?不过这里头会出现一些小问题!

// 21、流插入函数重载
ostream& operator<<(ostream& out)
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
	return out;
}

// 22、流提取函数重载
istream& operator>>(istream& in)
{

	while (1)
	{
		cout << "请输入合法日期>" << endl;
		cout << "年:";
		cin >> _year;
		cout << "月:";
		cin >> _month;
		cout << "日:";
		cin >> _day;
		cout << "-----------------" << endl;
		if (!CheckDate())
		{
			cout << "输入非法日期:";
			Print();
		}
		else
		{
			break;
		}
	}
	return in;
}

当我们定义到类里面时,参数列表中的第一个参数默认是隐含的(Date* const this) ,这恰好与我们在全局外定义的相反,从而导致如果我们在使用该函数时按照我们的习惯去写的话,编译器会直接报错!

必须这样书写! 

Date d1, d2;
d1 >> cin;
d1 << cout;

 我们可以看到这非常不符合我们的习惯!所以我们将他们定义到全局中,方便我们进行参数的调整。但我们又面临如何访问到类内部私有成员的问题,有以下几种方法:

1、将私有成员直接放开为public(最挫的方法)

2、提供get方法得到私有成员

3、使用友元函数

4、重载为成员函数(这里因参数问题就不可用了)

我这里使用了友元函数的方法(到后面我会具体讲解该函数的!)

22、流提取函数重载 

// 22、流提取函数重载
istream& operator>>(istream& in, Date& d)
{
	
	while (1)
	{
		cout << "请输入合法日期>" << endl;
		cout << "年:";
		cin >> d._year;
		cout << "月:";
		cin >> d._month;
		cout << "日:";
		cin >> d._day;
		cout << "-----------------"<<endl;
		if (!d.CheckDate())
		{
			cout << "输入非法日期:";
			d.Print();
		}
		else
		{
			break;
		}
	}
	return in;
}

3.3Test.cpp

下面代码是我在实现日期类时的检测(仅供参考)

#include"Date.h"

void Test1()
{
	Date d1(2024, 7, 21);
	Date d2(2024, 7, 22);

	Date d3 = d1;
	d3.Print();

	d3 = d2;
	d3.Print();

	Date d4=d3 + 3000;
	d4.Print();

}


void Test2()
{
	Date d1(2024, 7, 23);
	/*d1 -= 100;
	d1.Print();*/

	/*++d1;
	d1.Print();

	Date ret=d1++;
	ret.Print();
	d1.Print();*/
}

void Test3()
{
	Date d1(2024, 7, 21);
	Date d2(2024, 7, 22);
	bool ret = d1 >= d2;
	cout << ret << endl;
	int ret1 = d1 - d2;
	cout << ret1 << endl;
}

void Test4()
{
	Date d1(2050, 3, 21);
	Date d2(2024, 7, 22);
	/*bool ret = d1 >= d2;
	cout << ret << endl;*/
	int ret1 = d1 - d2;
	cout << ret1 << endl;
}

void Test5()
{
	Date d1, d2;
	cin >> d1 >> d2;
	cout << d1 << d2;
}

int main()
{
	//Test1();
	//Test2();
	//Test3();
	//Test4();
	Test5();
	return 0;
}

4.完结散花

好了,这期的分享到这里就结束了~

如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~

如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~

我们下期不见不散~~

​​​​

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

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

相关文章

【论文解读】大模型算法发展

一、简要介绍 论文研究了自深度学习出现以来&#xff0c;预训练语言模型的算法的改进速度。使用Wikitext和Penn Treebank上超过200个语言模型评估的数据集(2012-2023年)&#xff0c;论文发现达到设定性能阈值所需的计算大约每8个月减半一次&#xff0c;95%置信区间约为5到14个月…

React中的无状态组件:简约之美

&#x1f389; 博客主页&#xff1a;【剑九 六千里-CSDN博客】 &#x1f3a8; 上一篇文章&#xff1a;【掌握浏览器版本检测&#xff1a;从代码到用户界面】 &#x1f3a0; 系列专栏&#xff1a;【面试题-八股系列】 &#x1f496; 感谢大家点赞&#x1f44d;收藏⭐评论✍ 引言…

OS:处理机进程调度

1.BackGround&#xff1a;为什么要进行进程调度&#xff1f; 在多进程环境下&#xff0c;内存中存在着多个进程&#xff0c;其数目往往多于处理机核心数目。这就要求系统可以按照某种算法&#xff0c;动态的将处理机CPU资源分配给处于就绪状态的进程。调度算法的实质其实是一种…

使用 ComfyUI 跑 SD 图,就两个字:惊艳!

大家好&#xff0c;我是想象&#xff0c;AI 破局 9 颗 AI 之心持有者。ComfyUI 已经出来有一段时间了&#xff0c;一直没有深入去学习过&#xff0c;今天花了点时间跑了一下。体验下来&#xff0c;就两个字&#xff1a;惊艳&#xff01; 这张 3 个小丑的图&#xff0c;很真实吧…

MT6816磁编码IC在自动缩口机中的应用

随着工业自动化的快速发展&#xff0c;各种智能传感器与执行器在制造业中发挥着越来越重要的作用。其中&#xff0c;磁编码IC以其高精度、高可靠性以及优秀的环境适应性&#xff0c;成为了工业自动化控制中不可或缺的一部分。本文将详细介绍MT6816磁编码IC在自动缩口机中的应用…

【数字】三态门,双向端口,HDL描述

#工作记录# 之前工作的时候&#xff0c;负责GPIO的同事被负责人问“三态的en开启的时候是直通的吗&#xff1f;” 他支支吾吾的回答“是的吧”&#xff0c;负责人又问了一句&#xff0c;他就有点不自信了&#xff0c;顺手记录一下这个在SoC设计中非常常见的逻辑。 目录 一、…

Python爬虫 instagram API获取instagram帖子数据信息

这个instagram接口可以通过url链接直接获取相关帖子信息。如有需求&#xff0c;可点击文末链接联系我们。 详细采集页面 https://www.instagram.com/p/CqIbCzYMi5C/ 请求参数 返回示例 { "__typename": "GraphSidecar", "accessibility_caption&qu…

STM32H7串口中断服务函数会禁止中断

STM32H7 在中断服务函数HAL_UART_IRQHandler中&#xff0c;会禁止接收中断 同时也会禁止发送完成中断&#xff0c;调用UART_EndTransmit_IT来进行操作

微信小程序-自定义组件生命周期

一.created 组件实例创建完毕调用。定义在lifetimes对象里。 不能在方法里面更改data对象里面的值&#xff0c;但是可以定义属性值。 lifetimes:{//不能给data设置值created(){this.testaaconsole.log("created") }}二. attached 模板解析完成挂载到页面。 可以更…

Unity:PC包直接查看Log日志

PC端会输出Log日志&#xff0c;位置在&#xff1a; C:\Users\用户名\AppData\LocalLow\公司名\项目名 在这里可以找到类似的文件&#xff1a; 打开便可以看到打印。

提交高通量测序原始数据到 SRA --- 操作流程

❝ 写在前面 由于最近在提交课题数据到 NCBI 数据库&#xff0c;整理了相关笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. 提交高通量测序数据到 GEO --- 说明书 目录 1 注册 NCBI 账…

RedHat9 | Tomcat服务器部署

一、相关知识 Tomcat介绍 Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;下的一个开源项目&#xff0c;主要用于实现 Java Servlet、JavaServer Pages (JSP)、Java Expression Language (JEL) 以及 Java WebSocket 技术的容器。作为轻量级的…

YOLOv8改进 | 融合改进 | C2f结合可变形大核注意力超越自注意力【含Seg、OBB、OD代码】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

Linux进程间通信(管道,命名管道/FIFO,消息队列)

目录 前言 一、管道 二、命名管道/FIFO 三、消息队列 前言 前面我们学习了Linux进程编程的相关函数&#xff0c;也举了几个进程编程的实际应用场景&#xff1b;我们之前学到父进程等待子进程退出时也涉及到了一些进程间通信的概念&#xff0c;比如子进程调用exit函数&#…

AWS DMS MySQL为源端,如何在更改分区的时候避免报错

问题描述&#xff1a; 文档[1]中描述MySQL compatible Databases作为DMS任务的源端&#xff0c;不支持MySQL 分区表的 DDL 更改。 在源端MySQL进行分区添加时&#xff0c;日志里会出现如下报错&#xff1a; [SOURCE_CAPTURE ]W: Cannot change partition in table members…

2024年普通人怎么利用AI工具赚钱?

在当今这个信息爆炸的时代&#xff0c;AI技术的应用如同一股不可阻挡的潮流&#xff0c;为普通人开辟了全新的赚钱途径。以下是一些普通人就可以做的赚钱方法&#xff1a; 1、信息差模式 现在市场上AI应用工具很多&#xff0c;不是所有人都会对这些工具进行深入学习和测试&am…

网络访问(Socket/WebSocket/HTTP)

概述 HarmonyOS为用户提供了网络连接功能&#xff0c;具体由网络管理模块负责。通过该模块&#xff0c;用户可以进行Socket网络通滚、WebSocket连接、HTTP数据请求等网络通信服务。 Socket网络通信&#xff1a;通过Socket(嵌套字)进行数据通信&#xff0c;支持的协议包括UDP核…

iOS开发设计模式篇第一篇MVC设计模式

目录 1. 引言 2.概念 1.Model 1.职责 2.实现 3.和Controller通信 1.Contrller直接访问Model 2.通过委托(Delegate)模式 3.通知 4.KVO 4.设计的建议 2.View 1.职责 2.实现 3.和Controller通信 1. 目标-动作&#xff08;Target-Action&#xff09;模式 2…

matlab gui下的tcp client客户端编程框架

GUI界面 函数外定义全局变量 %全局变量 global TcpClient; %matlab作为tcpip客户端 建立连接 在“连接”按钮的回调函数下添加以下代码&#xff1a; global TcpClient;%全局变量 TcpClient tcpip(‘192.168.1.10’, 7, ‘NetworkRole’,‘client’); %连接到服务器地址和端…

免费【2024】springboot北京医疗企业固定资产管理系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…