c++类(中)续

news2024/9/28 11:15:11

c++类(中)续

  • 一、日期类
    • (1)什么是日期类?
    • (2)日期类的初始化与销毁
    • (3)我们需要完成的操作
      • (1)初始化与输出日期
      • (2)日期加等于天数
      • (3)日期加天数
      • (4)日期减等天数与减天数
      • (4)两日期之间的关系
      • (5)日期前置++与后置++
      • (6)两日期相减
      • (7)固定化格式输出输入日期
  • 二、取地址运算符重载
    • (一)const成员函数
    • (二)取地址运算符重载

这一章我们要完成的任务有:

一、日期类

(1)什么是日期类?

首先日期类就类似于网络上的日期计算器,那我们为什么要完成这个东西呢?
这是因为日期类中需要运用很多我们前面c++类的知识,可以更好的帮助我们理解c++类。
在这里插入图片描述
我们需要完成类似的工作。

(2)日期类的初始化与销毁

我们要完成日期类的初始化与销毁,那初始化是不是需要我们的构造函数,销毁需要我们的析构函数,那日期类需要初始化无非是年月日,我们需要构造函数来满足我们的初始化操作,但是我们需要析构函数吗,上一章我们学过如果没有申请空间那么我们就可以使用默认的析构函数即可。

所以在下面我们只需要完成构造函数即可。

(3)我们需要完成的操作

这里我们采用申明与定义分离的方式。
.h文件里

#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 2000, int month = 1, int day = 1);
	void print();
	bool operator<(Date& d);
	bool operator<=(Date& d);
	bool operator>(Date& d);
	bool operator>=(Date& d);
	bool operator==(Date& d);
	bool operator!=(Date& d);
	//比较两日期
	Date& operator+=(int day);
	Date operator+(int day);
	Date& operator-=(int day);
	Date operator-(int day);
	//日期加减天数
	int operator-(Date& d);
	//两日期之间隔的天数,会自动选出大的日期与小的日期,然后相减
	Date operator++(int);//后置++
	Date operator++();//前置++
	//流运算符重载
	void operator<<(ostream* out);//有问题
	void operator>>(istream* in);//有问题
private:
	int _year;//年
	int _month;//月
	int _day;//日
};

大家可以看到最后两个函数是有问题的大家可以思考为什么有问题,这两个函数我会留到最后解决。

(1)初始化与输出日期

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
void Date::print()
{
	cout << _year << ':' << _month << ':' << _day << endl;
}

这一部分很简单,大家看看就行了。

(2)日期加等于天数

首先我们需要明白日期加天数有两种情况:
在这里插入图片描述
如果是前者那就好办许多,如果是后者的话我们这里使用进位的方式,
什么意思?
就是当相加后的天数大于当前月的天数,我们就减去当前月的天数,然后月份加加,当我们的月加到13我们就将年加加,月置为1,这样就可以完美的解决问题,但是怎么获取当前月的天数呢?所以我们需要一个函数来获取当前月的天数

class Date
{
public:
	Date(int year = 2000, int month = 1, int day = 1);
	void print();
	bool operator<(Date& d);
	bool operator<=(Date& d);
	bool operator>(Date& d);
	bool operator>=(Date& d);
	bool operator==(Date& d);
	bool operator!=(Date& d);
	//比较两日期
	Date& operator+=(int day);
	Date operator+(int day);
	Date& operator-=(int day);
	Date operator-(int day);
	//日期加减天数
	int operator-(Date& d);
	//两日期之间隔的天数,会自动选出大的日期与小的日期,然后相减
	Date operator++(int);//后置++
	Date operator++();//前置++
	//流运算符重载
	void operator<<(ostream& out);//有问题
	void operator>>(istream& in);//有问题

	int GetMonthDay(int year, int month)
	{
		int MonthDay[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//第一个位置置0或者负数,因为我们
		//是通过月份来作为数组下标来访问我们的天数,而0月是不合法的
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			return 29;
		else
			return MonthDay[month];
	}
private:
	int _year;
	int _month;
	int _day;
};

大家可以看到我们将这个函数定义在类里,前面我们学过定义在类里的函数默认内联,内联函数一般运用与代码量少且频繁调用,这里获取天数的函数大家想一想是不是非常频繁啊。
然后我们再看代码部分,这里我们采用数组的形式来返回天数,大家如果想不到的话也可以用if,else if嵌套或者switch case语句,但是论简单的话还是数组比较简单,最后看我们如何判断闰年的2月与平年的2月的,只有闰年的2月才返回29其他都直接返回month下标的数组元素即可,此外,返回29这里有些同学想着更改数组元素,但我们下次再调用的时候这里的2月都被更改为29了。

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;//this指针隐藏,但在函数里我们可以使用
}

这就是我们的代码了。
然后我们再看我们的逻辑,我们是不是改变了我们原本的日期啊,那日期加天数是不是不能改变目前的日期,那我们就写不改变的加。

(3)日期加天数

这里我们是可以偷懒的,上面我们不是写了加等吗,那我们创建一个新的对象然后用新的对象加等,这就是我们的加的逻辑。
偷懒版:

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

那有些同学非要自己写该怎么写呢?

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

完成这些以后,细心的同学可能会发现我们的加返回并没有用引用,这是因为我们在这个函数里创建的新的对象,出了这个函数这个对象就销毁了,那如果我们传引用就会造成我们的野引用。

此外我们再了解一个知识点,我们上面用的的+复用+=等,那我们可不可以用+=复用+?并且哪里效率高?
这里我们直接给答案可以,并且**+复用+=效率高。**
在这里插入图片描述
红色圈起来的部分就是我们调用拷贝构造的地方,大家可以很明显的看到右边明显多了几次,准确的来说多了3次。

(4)日期减等天数与减天数

减等与减之间的关系与加与加等的关系类似,所以我在这里只给出代码,大家可以对比来理解。

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

在这里插入图片描述

(4)两日期之间的关系

两个日期之间的关系有>,>=,<,<=, ==, !=, 这里我们其实只需要完成两个即可。
为什么?例如我们完成 > 与 等于,那<不就是!>=,<=就是!>,这样来复用都可以完成。

<:

bool Date::operator<(Date& d)
{
	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;
}

相信我如果不说复用的话大家可能直接改个符号就是其他的函数了,当然也没有错,但这里能省则省。
等于:

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

当我们完成上面的我们就可以复用于其他函数了

bool Date::operator<(Date& d)
{
	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;
}
bool Date::operator<=(Date& d)
{
	return (*this == d) || (*this < d);
}
bool Date::operator>(Date& d)
{
	return !(*this <= d);
}
bool Date::operator>=(Date& d)
{
	return !(*this < d);
}
bool Date::operator==(Date& d)
{
	return _year == d._year &&
		_month == d._month &&
		_day == d._day;
}
bool Date::operator!=(Date& d)
{
	return !(*this == d);
}

(5)日期前置++与后置++

前置++是先++再使用,后置++是先使用再++

Date Date::operator++(int)
{
	Date d = *this;
	*this += 1;
	return d;
	//后置++是先使用原本的值再++
	// int a=0,x=1;
	//例如int x+=a++;,执行完x=1,a=1,这里逻辑一样。
}
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

在这里插入图片描述

(6)两日期相减

两日期相减我们有两种思路
一、在这里插入图片描述
二、在这里插入图片描述
这里我们只说第二种,第二种什么意思呢?
我们上面不是完成了日期++吗,那我们让小的日期一直++直到等于大的日期,那++的次数不就是相差的天数。
代码:

int Date::operator-(Date& d)
{
	Date Max = *this > d ? *this : d;//选出大的日期
	Date Min = *this > d ? d : *this;//选出小的日期
	int count = 0;//记录++次数也就是天数
	while (Min != Max)
	{
		Min++;
		count++;
	}
	return count;
}

完成了上面的我们的日期类就差不多了。

(7)固定化格式输出输入日期

上面我们的日期类都是给定值然后再计算,那我们能不能自己输入日期呢和输出日期就是我们需要完成的,我们将这种输出输入叫做以固定格式输入与输出,在c语言中sacnf与printf就是这种方式
其实上面在.h文件中我也提到过:
void operator<<(ostream& out);//有问题
void operator>>(istream& in);//有问题
ostream 与 istream 是我们的标准输入输出流,大家要不不了解可以去看一下我写的文件这一节。
但这里的问题不是不能输出与输入,而是不符合语法。
我们现在写一下:

void Date::operator<<(ostream& out)//有问题
{
	out << _year << ':' << _month << ':' << _day << endl;
}
void Date::operator>>(istream& in)//有问题
{
	in >> _year >> _month >> _day;
}

为什么我说它有问题呢我们可以看:
在这里插入图片描述
大家可以看到是能输出的,但是它的写法不符合我们的习惯,所以我们就pass掉
那大家知道为什么会出现这种情况吗?在上一节c++中我们不是说过c类里的函数隐含有一个this指针,那我们的>><<就是有两个操作数,而我们上一节又说了左操作数会默认在操作符的左边,右操作数在操作符的右边故此导致这种情况!!!

所以我们只能放在类外来实现,但是类外无法访问我们的类的类部成员,这怎么办?这里有两种解决办法,第一种使用get函数。
例如:

class point
{
	int getx()
	{
		return x;
	}
private:
	int x;
};

第二种方式将其定义为友元函数。

class Date
{
public:
	Date(int year = 2000, int month = 1, int day = 1);
	void print();
	bool operator<(Date& d);
	bool operator<=(Date& d);
	bool operator>(Date& d);
	bool operator>=(Date& d);
	bool operator==(Date& d);
	bool operator!=(Date& d);
	//比较两日期
	Date& operator+=(int day);
	Date operator+(int day);
	Date& operator-=(int day);
	Date operator-(int day);
	//日期加减天数
	int operator-(Date& d);
	//两日期之间隔的天数,会自动选出大的日期与小的日期,然后相减
	Date operator++(int);//后置++
	Date& operator++();//前置++
	//流运算符重载
	//void operator<<(ostream& out);//有问题
	//void operator>>(istream& in);//有问题

	int GetMonthDay(int year, int month)
	{
		int MonthDay[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//第一个位置置0或者负数,因为我们
		//是通过月份来作为数组下标来访问我们的天数,而0月是不合法的
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			return 29;
		else
			return MonthDay[month];
	}
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

写法跟上面有问题的写法一样的

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << ':' << ':' << d._month << ':' << d._day << endl;
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

在这里插入图片描述
最后我们来说明一下为什么我们的返回值是ostream与istream,我们之前内置类型是不是可以连续输入与输出,其实质就是从左到右连续输入与输出。
在这里插入图片描述
以上就是日期类的全部内容,这里涉及到了许多类的知识,希望大家能够全部理解。

二、取地址运算符重载

(一)const成员函数

1、将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后⾯。
2、const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。const 修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 constDate* const this
在这里插入图片描述
这里是很标准的权限放大,实际下面是Dateconst this 但是这里的const修饰的本身,上面是禁止修改我们的对象,下面是禁止修改指针,怎么解决呢?在下面的Date前加const
在这里插入图片描述
祖师爷为了解决这个问题就在函数的参数列表后加const, 如上图所示。

//本质print(const Date*const this)
void Date::print()const
{
	cout << _year << ':' << _month << ':' << _day << endl;
}

如果我们的非const对象调用,这里属于权限缩小,这里是可以调用的。

总结:不修改成员变量的函数都可以加const。

(二)取地址运算符重载

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

Date* operator&()
{
	return nullptr;//这里我不想别人取到对象地址
}
const Date* operator&()const
{
	return this;//这里一定返回对象地址
}

没有实际意义,只是作为了解。

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

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

相关文章

Linux实现进度条小程序——缓冲区

&#x1f4dd;Linux实现进度条小程序 &#x1f4dd; 行缓冲区&#x1f4dd; fflush函数&#x1f4dd; 示例&#x1f4dd; 进度条如何编译运行proc.hproc.cmain.c 好雨知时节 当春乃发生 随风潜入夜 润物细无声 回车换行其实是两个概念&#xff0c;一是回车&#xff0c;一是换行…

JAVA毕业设计167—基于Java+Springboot+vue3+小程序的物业管理系统小程序(源代码+数据库+万字论文+文献综述)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue3小程序的物业管理系统小程序(源代码数据库万字论文文献综述)167 一、系统介绍 本项目前后端分离带小程序(可以改为ssm版本)&#xff0c;分为用户、管理员两…

微服务--认识微服务

微服务架构的演变 1. 单体架构&#xff08;Monolithic&#xff09; 阶段描述&#xff1a;在单体应用时代&#xff0c;整个应用程序被设计为一个项目&#xff0c;并在一个进程内运行。这种架构方式开发简单&#xff0c;便于集中管理&#xff0c;但随着应用的复杂化&#xff0c…

[000-01-008].第01节:Nacos开发应用

我的后端学习大纲 SpringCloud学习大纲 2.Nacos功能&#xff1a; Nacos可以作为服务的注册中心&#xff0c;也可以作为服务配置中心&#xff1a; 服务发现与服务健康检查:Nacos使服务更容易注册,并通过DNS或HTTP接口发现其他服务&#xff0c;Nacos还提供服务的实时健康检查&…

无人机遥控器工作原理!!!

一、基本组成 无人机遥控器通常由发射端&#xff08;遥控器本体&#xff09;和接收端&#xff08;安装在无人机上的接收模块&#xff09;两部分组成。发射端包含控制杆、按钮、显示屏等物理控件&#xff0c;用于输入控制指令&#xff1b;接收端则负责接收来自发射端的无线电信…

机器人外呼的具体操作步骤是怎样的?

今天小编给大家整理一下几点关于使用AI机器人拨打电销电话的具体步骤可以归纳为以下几个关键环节&#xff1a; ​ ### 一、选择合适的AI机器人服务 1. **平台选择**&#xff1a; - 选择一个提供AI机器人拨打电话服务的平台&#xff0c;这可以是云端的AI电话机器人服务&#…

关于docker-maven-plugin在arm架构的机器上制作镜像报错

背景 客户环境提供的容器集群全是arm架构&#xff0c;因此打包时要在arm架构的电脑上来制作镜像&#xff0c;本人使用mac m3芯片macbook&#xff0c;但是执行mvn clean package -D maven.test.skiptrue docker:build 命令时报错&#xff0c;报错信息如下&#xff1a; Caused …

数据分析及应用:如何分析基于绝对中位差的异常值检测问题?

目录 0 场景描述 1 数据准备 2 问题分析 abs(rn - (cnt+1)/2) < 1 3 小结 0 场景描述 数据集中可能存在异常的值。值存在异常有多种原因: (1)可能是数据收集方式有问题,比如记录值的仪表存在误差;(2)可能是数据输入错误导致的;(3)还可能是因为数据生成时环境…

基于web 在线影院系统网站设计与实现

3.1 系统基本情况描述 在线影院系统需要实现的功能包括用户的管理&#xff0c;以及视频信息的管理和使用等。具体来讲&#xff0c;它包含用户管理中常见的注册、登录操作&#xff0c;视频信息的显示、播放、搜索操作&#xff0c;视频管理中的添加、删除、修改等。同时为了方便…

【VScode环境配置】在VScode中配置php环境(wamp版)

1.前置准备 1.wamp&#xff08;集成环境&#xff09; 2.Visual Studio Code 2.系统变量配置 1.打开php所在路径&#xff1a; 一般在你所安装的wamp的bin目录文件夹下。wamp可以自定义安装路径&#xff0c;每个人的位置不一样&#xff0c;这里是拿作者的路径作为演示。 C:…

Golang | Leetcode Golang题解之第382题链表随机节点

题目&#xff1a; 题解&#xff1a; type Solution struct {head *ListNode }func Constructor(head *ListNode) Solution {return Solution{head} }func (s *Solution) GetRandom() (ans int) {for node, i : s.head, 1; node ! nil; node node.Next {if rand.Intn(i) 0 { …

mysql与es数据同步

同步方案 1. 同步双写 同步双写是一种数据同步策略&#xff0c;它指的是在主数据库&#xff08;如MySQL&#xff09;上进行数据修改操作时&#xff0c;同时将这些修改同步写入到ES中。这种策略旨在确保两个数据库之间的数据一致性&#xff0c;并优化系统的读写性能。 目标 …

es映射配置(_mapping)

文章目录 1、创建映射字段2、查看映射关系 1、创建映射字段 PUT /索引库名/_mapping {"properties": {"字段名": {"type": "类型","index": true&#xff0c;"store": true&#xff0c;"analyzer": &q…

python-矩阵交换行

[题目描述] 给定一个 55 的矩阵(数学上&#xff0c;一个 rc 的矩阵是一个由 r 行 c 列元素排列成的矩形阵列)&#xff0c;将第 n 行和第 m 行交换&#xff0c;输出交换后的结果。输入&#xff1a; 输入共 6 行&#xff0c;前 5 行为矩阵的每一行元素&#xff0c;元素与元素之间…

行业Know How在AI提示词中的重要性

现在AI这玩意儿可是火得不得了,ChatGPT、Claude这些大语言模型简直是让人眼花缭乱。可是呢,你要是不会用,那就跟给猴子一部iPhone有啥区别? 咱得明白,这AI不是神仙,它也是需要"调教"的。 你给它的提示词就像是给小孩子布置作业,说得不清不楚,它可能就给你整出些稀奇…

NPC框架

NPC框架在不同领域可能有不同的含义和应用。在软件开发和游戏设计领域,NPC(Non-Player Character,非玩家角色)框架通常与角色控制、行为模拟和交互逻辑等方面相关。以下是对NPC框架的一种概括性解释: NPC框架概述 定义: NPC框架是指在软件开发或游戏设计中,用于创建、…

深入探索.NET Flyleaf的高级特性与最佳实践

文章目录 前言一、高级特性1.强大的扩展性2.高性能3.易开发4.广泛兼容性5.自定义性强6.多语言支持 二、最佳实践1.定制化界面开发2.性能优化3.插件集成4.跨平台部署5.安全性考虑 三、应用案例1.案例一&#xff1a;个人媒体中心2.案例二&#xff1a;教育平台3.案例三&#xff1a…

国内首批!文心快码获中国信通院评测AI智能编码工具4+级

&#x1f381;&#x1f449;点击进入文心快码 Baidu Comate 官网&#xff0c;体验智能编码之旅&#xff0c;还有超多福利&#xff01;&#x1f381; 国内首批&#xff01;文心快码获中国信通院评测AI智能编码工具4级 在当下这个快节奏的开发时代&#xff0c;每一个程序员都在追…

爆肝熬夜整理出来的百道Python基础必刷题!(附加源码和答案)

一、前言 一个python入门初学者如何学代码,读代码和写代码&#xff0c;我想学代码不知道方向谁能给我指明一个方向?对于c语言来说&#xff0c;要记得东西其实不多&#xff0c;基本就是几个常用语句加一些关键字而已。你所看到的那些几千甚至上万行的代码&#xff0c;都是用这…

零基础学习Redis(9) -- set类型命令使用

set&#xff0c;即集合和list类似&#xff0c;集合中的每个元素都是string类型&#xff0c;但是集合中的元素是无序且不能重复的 1. 增删查操作 1.1 增加元素 sadd key member1 menber2 ... 在key中添加一个或多个menber1 &#xff0c;返回添加成功的数量&#xff0c;添加每…