首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C++新旅程:日期类的实现

C++新旅程:日期类的实现

原创
作者头像
池央
修改2024-11-26 00:07:56
修改2024-11-26 00:07:56
2500
举报
文章被收录于专栏:好事连连好事连连

好事发生

Java面试宝典:MongoDB实战技巧 作者:忆遂愿

https://cloud.tencent.com/developer/article/2466159?shareByChannel=link

文章对 MongoDB 知识的全面阐述,质量很高。从基本概念、Java 驱动使用、数据操作、安全性能问题与解决、数据一致性事务处理,到数据模型设计、技术集成和存储图片优势等方面讲解详细、条理清晰,体现出作者深入的理解。

要实现一个日期类我们先考虑一下他有什么成员?

必须有的:年、月、日

一、构造函数

对于构造函数,由于 Date 类的成员类型均为内置类型,虽然编译器在某些情况下能够自动生成默认构造函数,但为了代码的清晰性和可控性,我们可以显式地编写一个全缺省的构造函数。如下所示:

代码语言:c
复制
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

通过这个构造函数,我们能够方便地创建 Date 类对象,并在创建时为年、月、日成员赋予初始值。如果在创建对象时没有提供参数,对象将被初始化为默认的日期(例如 0 年 1 月 1 日)。

接下来我们再来考虑下日期类一般会有什么方法?

二、析构函数

考虑到成员都是内置类型,不存在需要手动释放的资源,因此不需要显式地编写析构函数。编译器生成的默认析构函数足以处理这类情况,它会自动执行一些基本的清理工作,如释放对象占用的内存空间等。

三、拷贝构造函数

在拷贝构造函数方面,编译器会自动提供一个默认的拷贝构造函数。这个默认的拷贝构造函数能够完成简单的成员变量值的拷贝操作,对于 Date 类这种成员为内置类型的情况,通常能够满足基本需求。然而,如果我们希望自定义拷贝构造函数的行为,也可以显式地编写。其实现如下:

代码语言:c
复制
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

拷贝构造函数的名称与类名相同,它接受一个常量引用类型的参数,该参数为需要拷贝的源对象。在函数体内,将源对象的成员变量值逐一赋值给当前对象的相应成员变量,从而实现对象的拷贝。

四、获取某个月的具体天数

日期类通常需要一个方法来获取指定月份的天数。因为不同月份的天数有所不同,并且还需要考虑闰年的情况。以下是获取某个月具体天数的函数实现:

代码语言:c
复制
int Date::GetMonthDay(int year, int month)
{
	static int MonthDay[13] = { -1,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];
	}
}

这里我们使用一个静态数组来存储每个月的天数信息,将数组长度设置为 13,以便数组下标能够与月份直接对应(其中下标 0 处的值 -1 可作为一种特殊标记或占位,无实际月份对应意义)。在函数中,首先判断是否为闰年的二月,如果是,则返回 29 天;否则,直接返回数组中对应月份的天数。

五、赋值运算符重载

编译器会自动生成默认的赋值运算符重载函数,但有时我们可能需要自定义其行为。显式实现赋值运算符重载函数时,需要注意一些关键要点。以下是其实现代码:

代码语言:c
复制
Date& Date::operator=(const Date& d)
{
	//检查自赋值
	if (this == &d)
	{
		return *this;
	}
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}

其返回值类型为类类型的引用,这样可以实现连续赋值操作(例如:a = b = c;)。形参为一个常量引用类型的参数,表示要赋值的源对象。在函数体中,首先进行自赋值检查,如果当前对象与源对象相同(即this指针指向的地址与源对象地址相同),则直接返回当前对象,避免不必要的赋值操作。然后,将源对象的成员变量值赋值给当前对象的成员变量,并最终返回当前对象的引用。

六、各种运算符重载

除了上述提到的运算符重载外,日期类还可能涉及其他运算符的重载,如日期的比较运算符(大于、小于、等于等)、日期的加减运算(例如计算两个日期之间的间隔天数,或者在某个日期上增加或减少一定天数得到新的日期)等。这些运算符重载的核心思想是复用已有的函数或方法,以提高代码的简洁性和可维护性。虽然这里不一一详细说明,但在实际实现中,可以根据具体的需求和逻辑进行设计与编写。

七、直接输入、输出日期

为了方便日期类对象的输入和输出操作,我们可以重载输入流运算符>>和输出流运算符<<。需要注意的是,它们并非日期类的成员函数,而是日期类的友元函数。友元函数的特点是可以访问类的所有成员,但由于它不属于类的成员函数,所以没有隐藏的this指针,因此需要传递两个参数。以下是其实现代码:

代码语言:c
复制
    friend ostream& operator<<(ostream& os, Date& d)
	{
		os << d._year << "/" << d._month << "/" << d._day << endl;
		return os;
	}
	friend istream& operator>>(istream& is, Date& d)
	{
		is >> d._year >> d._month >> d._day;
		return is;
	}

需要注意的是他们不是日期类的成员函数,而是日期类的友元函数,返回值类型前面加了关键字friend来修饰,注意友元函数虽然可以访问类的所有成员,但是由于他本身不是类的成员函数也就没有了隐藏的this指针,所以需要传两个参数.

八、具体代码

头文件

代码语言:c
复制
#pragma once
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 0, int month = 0, int day = 0);
	// 拷贝构造函数
	// d2(d1)
	Date(const Date& d);

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

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

	// 日期+=天数
	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);

	void print()const;
	// 析构函数(日期类无需清理资源,析构函数不必显示写)
	//~Date()
	//{
		//cout << "~Date()" << endl;
	//}
	friend ostream& operator<<(ostream& os, Date& d)
	{
		os << d._year << "/" << d._month << "/" << d._day << endl;
		return os;
	}
	friend istream& operator>>(istream& is, Date& d)
	{
		is >> d._year >> d._month >> d._day;
		return is;
	}
private:
	int _year, _month, _day;
};

函数的具体实现

代码语言:c
复制
#include"Date.h"
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;
}
// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	//检查自赋值
	if (this == &d)
	{
		return *this;
	}
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}
int Date::GetMonthDay(int year, int month)
{
	static int MonthDay[13] = { -1,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];
	}
}
void Date::print()const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
// >运算符重载
bool Date::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 Date::operator==(const Date& d)
{
	return _year == d._year && _month == d._month && _day == d._day;
}

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

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

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

// !=运算符重载
bool Date::operator != (const Date& d)
{
	return !(*this == d);
}
// 日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
		_day -= GetMonthDay(_year, _month);
	}
	return *this;
}

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

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

// 日期-=天数
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++()
{
	*this += 1;
	return *this;
}

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

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

// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	Date max(*this);
	Date min(d);
	int flag = 1;
	int count = 0;
	if (*this < d)
	{
		flag = -1;
		max = d;
		min = *this;
	}
	while (min < max)
	{
		min++;
		count++;
	}
	return count * flag;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 好事发生
  • 一、构造函数
  • 二、析构函数
  • 三、拷贝构造函数
  • 四、获取某个月的具体天数
  • 五、赋值运算符重载
  • 六、各种运算符重载
  • 七、直接输入、输出日期
  • 八、具体代码
    • 头文件
    • 函数的具体实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档