栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C++】日期类@类和对象(中)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C++】日期类@类和对象(中)

小练习 - 日期类

0. 引1. 基本接口

1.1 默认成员函数

1.1.1 构造函数1.1.2 拷贝构造函数 1.2 获取某年某月天数 2. 一系列运算符重载函数

2.1 `+=` 、`+`、`++`

2.2.1 日期 `+=` 天数 = ?2.2.2 日期 `+` 天数2.2.3 前置++、后置++ 2.2 `-=`、`-`、`--`

2.2.1 日期 `-=` 天数 = 日期2.2.2 日期 `-` 天数2.2.3 前置--、后置-- 2.3 一堆比较 `>`、`>=`、`<`、`<=`、`==`、`!=` 3. 日期 - 日期4. 星期几?附录:

`Date.cpp``test.cpp`

0. 引

继C++入门、类和对象上篇中篇后,我们把这些学到的知识都用起来,来写一个日期类。这不禁让我想起了闷热又潮湿的夏季小学期java的第一个作业,写一个万年历,那时我写的真是一塌糊涂啊哈哈。下面我贴出头文件,各位自己写。所有要注意的小点我都写出来了,文章尽量呈现一套自然而然理所当然的思路。开始吧!

#include
using namespace std;

class Date
{
public:
	//构造函数
	Date::Date(int year = 0, int month = 1, int day = 1);
	//析构函数、拷贝构造、赋值重载都不用写
	//Date(const Date& d)
	//{
	//	cout << "Date(const Date& d)" << endl;
	//}
	void Print();

	int getMonthDay(int year, int month);
	//运算符重载系列
	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);

	// d1 += 100;
	Date& operator+=(int day);
	// d1 + 100;
	Date operator+(int day);
	// d1 -= 100;
	Date& operator-=(int day);
	// d1 - 100;
	Date operator-(int day);
	
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 前置--
	Date& operator--();
	//后置 --
	Date operator--(int);

	// 日期 - 日期
	int operator-(const Date& d);
	// 今天是星期几?
	void PrintWeekday();
private:
	int _year;
	int _month;
	int _day;
};
1. 基本接口 1.1 默认成员函数 1.1.1 构造函数

通过对于构造函数、析构函数、拷贝构造这一系列函数特征的学习,我们知道对于日期类,我们并不需要写析构、拷贝构造一类,用默认的就行。只需要自己实现构造函数。

注:

  • 缺省参数不能在声明和定义中同时出现,一般写在声明中
    Date::Date(int year, int month, int day )
    {
    	_year = year;
    	_month = month;
    	_day = day;
    
    	if (year<0
    		||(month<0 || month >12)
    		||(day <0 || day >getMonthDay(year,month)))
    	{
    		cout << "非法日期:>";
    		Print(); //在类里,可以直接访问类函数
    	}
    }
    

    这就还需要考虑非法日期的输入:为了判断天数是否合理,我们引入了下一个接口,来获取某年某月的天数 ——

    1.1.2 拷贝构造函数

    可以不写。但后面我为了验证拷贝构造函数的调用,在里面瞎写了一句打印。

    1.2 获取某年某月天数

    这里采用了比较巧妙的用数组存储天数,第几月就对应着相应天数。

    注:

  • 对于天数,不会修改,置为静态数组。
  • 对闰年的处理,先来判断month == 2
    int Date::getMonthDay(int year, int month)
    {
    	//静态数组
    	static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    	int day = monthDayArray[month];
    	//闰年:四年一闰、百年不闰、四百年再闰
    	if (month == 2
    		&& ((year%4==0 && year%100!=0)||( year%400 == 0)))
    	{
    		day += 1;
    	}
    	return day;
    }
    
    2. 一系列运算符重载函数 2.1 += 、+、++ 2.2.1 日期 += 天数 = ?

    2022.1.21 + 100是几号?这个功能的实现,乍一想好像挺复杂,还要考虑闰年,不同月的天数。但顺着我们正常的计算思维,列写几个例子,其实很简单。✅它其实就是一个不断进位的过程,天满了往月进;月满了往年进、月归1。

    那就写个循环直至合法 ——

    Date& Date::operator+=(int day)
    {
    	_day += day;
    	while (_day > getMonthDay(_year, _month))
    	{
    		_day -= getMonthDay(_year, _month);
    		_month++;
    
    		if (_month == 13)
    		{
    			_year += 1;
    			_month = 1;
    		}
    	}
    	return *this;//d1没销毁,可以传引用返回
    }
    

  • 注意,这里我们实现的是+=,而不是 +,在这里我们改变了d1,回想,我们之前多次强调过
    	int i = 0;
    	i + 100;
    

    i的值并不会改变。那怎么实现运算符+的重载呢?我们就弄一个临时对象来 ——

    2.2.2 日期 + 天数

  • 拷贝构造一个临时对象,以避免对d的改变
  • 可以巧妙复用+=接口
    // d1 + 100; 不能改变d1
    Date Date::operator+(int day)
    {
    	Date ret(*this);//拷贝构造一个
    	ret += 100; // ret.operator+=(&ret, 100);
    	return ret;
    }
    
    2.2.3 前置++、后置++

    在写++的运算符重载函数时,发现这两个函数啊,函数名相同。为了区分前置++和后置++,我们增加一个参数占位,它们俩就构成了函数重载。

    实现:前置++,与后置++,区别就在于返回值的不同。

  • 注意:究竟传引用返回(能不能?),还是传值返回 —— 不是背出来一开始就写上的。而是根据你实现的的不同逻辑,看你返回的对象,出了作用域被没被销毁,分析出来加上的,当然熟练了就直接写了。

    前置++

    // 先++后使用
    Date& Date::operator++()
    {
    	*this += 1;
    	return *this;
    }
    

    后置++

    // 先使用后++
    Date Date::operator++(int)
    {
    	Date ret(*this);
    	*this += 1;
    	return ret;
    }
    

    注:

  • 如何调用?

    编译器会把它们转化为 ——

    	Date d1(2022, 1, 22);
    	++d1; //d1.operator(&d1);
    	d1++; //d1.operator(&d1, 1); 
    

    后置++,这个整数只起到占位作用,没有实在意义,所以传什么随意。

  • 对于整型,前置++后置++区别不大(不涉及使用返回值时),但是对于自定义类型,建议使用前置++。这是因为前置++,我们可以传引用返回;后置++,拷贝构造临时对象加上传值返回,要拷贝构造两次(调试/打印可测,我都测了哈),效率低下。
    所以你看,**前置++**也保持了它原生的样子。 2.2 -=、-、--

    有了2.1节“加”的一系列铺垫,关于“减”那是不在话下。

    2.2.1 日期 -= 天数 = 日期

    怎么减呢?写过“加”了,那思路就顺下来。(在我测试的时候,把几个易错点全测到了,或许女生真的适合去做测试?哈哈,值得表扬的是通过调试都改过来了,也侧面说明我踩雷踩得相当准,我都写在注意里了)

    注意:

  • 天数 <= 0都不合法
  • 注意我们借到的天数是上一个月的天数(这与“加”不同,“加”获取的是本月天数)。
  • 到达边界时,我们是先把月置12,再对天数处理(这与”加“也不同,这里是先处理月份,后处理天,光我说你可能晕了,自己想想者的逻辑很简单)。
    Date& Date::operator-=(int day)
    {
    	while (_day <= 0)
    	{
    		_month--;
    		if (_month == 0)
    		{
    			_year--;
    			_month = 12;
    		}
    		_day += getMonthDay(_year, _month);
    
    	}
    	return *this;
    }
    

    在这里要考虑,万一我输入的day是负数?

    我们需要把它单拎出来处理一下,-= day等价于+= (-day)。同样的刚刚我们实现的+=运算符重载函数也需要同样处理,代码如下 ——

    // +=
    Date& Date::operator+=(int day)
    {
    	if (day < 0)
    	{
    		return *this -= -day;
    	}
    	_day += day;
    	while (_day > getMonthDay(_year, _month))
    	{
    		_day -= getMonthDay(_year, _month);
    		_month++;
    		if (_month == 13)
    		{
    			_year += 1;
    			_month = 1;
    		}
    	}
    	return *this;//d1没销毁,可以传引用返回
    }
    
    //-=
    Date& Date::operator-=(int day)
    {
    	if (day < 0)
    	{
    		return *this += -day;
    	}
    	_day -= day;
    	while (_day <= 0)
    	{
    		_month--;
    		if (_month == 0)
    		{
    			_year--;
    			_month = 12;
    		}
    
    		_day += getMonthDay(_year, _month);
    
    	}
    	return *this;
    }
    
    2.2.2 日期 - 天数

    复用嗷!

    Date Date::operator-(int day)
    {
    	Date ret(*this);
    	ret -= day;
    	return ret;
    }
    
    2.2.3 前置–、后置–

    注意事项同++

    // 前置--
    Date& Date::operator--()
    {
    	*this -= 1;
    	return *this;
    }
    
    //后置 --
    Date Date::operator--(int)
    {
    	Date ret(*this);
    	*this -= 1;
    	return *this;
    }
    
    2.3 一堆比较 >、>=、<、<=、==、!=

    事实上,在我们实现了>、==,就可以根据这些符号简单的关系,疯狂复用完成其他所有接口。

    相似的逻辑,很自然的就能想到能不能复用。来!

    // >
    // d1>d2 => d1.operator(&d1, d2)
    bool Date::operator>(const Date& d)
    {
    	if (_year > d._year)
    	{
    		return true;
    	}
    	else if (_year == d._year && _month > d._month)
    	{
    		return true;
    	}
    	else if (_year == d._year && _month == d._month && _day > d._day)
    	{
    		return true;
    	}
    	else
    	{
    		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);
    }
    
    3. 日期 - 日期

    这乍一想是挺复杂,又可能是闰年,跨几个月也不定。其实可以暴力求解,找那个较小的日期,加加加到较大的日期。

    这里我计算一个,从今天到小边冲实习生那天还有多少天吧!诶,有高考倒计时的感觉了。来!

    // 日期 - 日期
    // offerDay - today => offerDay.operator(&offerday, today);
    int Date::operator-(const Date& d)
    {
    	// 假设
    	Date min = d;//早
    	Date max = *this;//晚
    	int flag = 1;
    	if (*this < d)
    	{
    		min = *this; //早
    		max = d; // 晚
    		flag = -1;
    	}
    
    	int count = 0;
    	while (min < max)
    	{
    		min++;
    		count++;
    	}
    	return count*flag;
    }
    

    4. 星期几?
    void Date::PrintWeekday()
    {
    	Date start(1900, 1, 1); //查询得星期一
    	int count = *this - start;
    	cout << "星期" << ((count % 7) + 1) << endl;
    }
    
    附录:

    测试文件随写随测

    Date.cpp
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include"Date.h"
    
    int Date::getMonthDay(int year, int month)
    {
    	//静态数组
    	static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    	int day = monthDayArray[month];
    	//闰年:四年一闰、百年不闰、四百年再闰
    	if (month == 2
    		&& ((year%4==0 && year%100!=0)||( year%400 == 0)))
    	{
    		day += 1;
    	}
    	return day;
    }
    
    //缺省参数不能在声明和定义中同时出现
    Date::Date(int year, int month, int day )
    {
    	_year = year;
    	_month = month;
    	_day = day;
    
    	if (year<0
    		||(month<0 || month >12)
    		||(day <0 || day >getMonthDay(year,month)))
    	{
    		cout << "非法日期:>";
    		Print(); //在类里,可以直接访问类函数
    	}
    }
    
    void Date::Print()
    {
    	cout << _year << "-" << _month << "-" << _day << endl; 
    }
    
    Date& Date::operator+=(int day)
    {
    	if (day < 0)
    	{
    		return *this -= -day;
    	}
    	_day += day;
    	while (_day > getMonthDay(_year, _month))
    	{
    		_day -= getMonthDay(_year, _month);
    		_month++;
    		if (_month == 13)
    		{
    			_year += 1;
    			_month = 1;
    		}
    	}
    	return *this;//d1没销毁,可以传引用返回
    }
    
    // d1 + 100; 不能改变d1
    Date Date::operator+(int day)
    {
    	Date ret(*this);//拷贝构造一个
    	ret += 100; // ret.operator+=(&ret, 100);
    	return ret;
    }
    
    // 前置++
    Date& Date::operator++()
    {
    	*this += 1;
    	return *this;
    }
    
    //后置++
    Date Date::operator++(int)
    {
    	Date ret(*this);
    	*this += 1;
    	return ret;
    }
    
    
    
    bool Date::operator>(const Date& d)
    {
    	if (_year > d._year)
    	{
    		return true;
    	}
    	else if (_year == d._year && _month > d._month)
    	{
    		return true;
    	}
    	else if (_year == d._year && _month == d._month && _day > d._day)
    	{
    		return true;
    	}
    	else
    	{
    		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)
    {
    	if (day < 0)
    	{
    		return *this += -day;
    	}
    	_day -= day;
    	while (_day <= 0)
    	{
    		_month--;
    		if (_month == 0)
    		{
    			_year--;
    			_month = 12;
    		}
    
    		_day += getMonthDay(_year, _month);
    
    	}
    	return *this;
    }
    
    Date Date::operator-(int day)
    {
    	Date ret(*this);
    	ret -= day;
    	return ret;
    }
    
    // 前置--
    Date& Date::operator--()
    {
    	*this -= 1;
    	return *this;
    }
    
    //后置 --
    Date Date::operator--(int)
    {
    	Date ret(*this);
    	*this -= 1;
    	return *this;
    }
    
    // 日期 - 日期
    // offerDay - today => offerDay.operator(&offerday, today);
    int Date::operator-(const Date& d)
    {
    	// 假设
    	Date min = d;//早
    	Date max = *this;//晚
    	int flag = 1;
    	if (*this < d)
    	{
    		min = *this; //早
    		max = d; // 晚
    		flag = -1;
    	}
    
    	int count = 0;
    	while (min < max)
    	{
    		min++;
    		count++;
    	}
    	return count*flag;
    }
    
    void Date::PrintWeekday()
    {
    	Date start(1900, 1, 1); //查询得星期一
    	int count = *this - start;
    	cout << "星期" << ((count % 7) + 1) << endl;
    }
    
    test.cpp
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include "Date.h"
    
    void test1()
    {
    	Date d1(2002, 3, 7);
    	d1.Print();
    
    	Date d2(2022, 2, 29);
    }
    
    //测试+、+=、++
    void test2()
    {
    	Date d1(2022, 1, 16);
    	
    
    	//Date d2(2022, 1, 16);
    	//d2 += 100;
    	//d2.Print();
    
    	//++d1;
    	d1++;
    }
    
    //测试这一堆运算符重载函数
    void test3()
    {
    	
    	Date d1(2002, 3, 7);
    	Date d2(2002, 2, 19); //missing lmyy
    	Date d3(2002, 3, 7);
    
    	cout << (d1 == d3) << endl;
    	cout << (d1 >= d2) << endl;
    	cout << (d1 < d3) << endl;
    	cout << (d1 <= d2) << endl;
    	cout << (d1 != d3) << endl;
    
    }
    
    // 测试-,-=,--
    void test4()
    {
    	Date d1(2022, 1, 10);
    	Date d2(2022, 2, 19);
    
    	Date ret2 = d2 - 60;
    	ret2.Print();
    
    	d1 -= 10;
    	d1.Print();
    
    	
    }
    
    //测试日期 - 日期,星期几
    void test5()
    {
    	Date today(2022,1,23);
    	Date offerDay(2022, 9, 1);
    	cout << (offerDay - today) << endl;
    	today.PrintWeekday();
    }
    
    int main()
    {
    	//test1();
    	//test2();
    	//test3();
    	//test4();
    	test5();
    	return 0;
    }
    
  • 转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/713739.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号