前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【C++】类和对象练习——日期类的实现

【C++】类和对象练习——日期类的实现

作者头像
用户11292525
发布2024-11-21 15:59:49
发布2024-11-21 15:59:49
7800
代码可运行
举报
文章被收录于专栏:学习学习
运行总次数:0
代码可运行

实现功能:

1.h文件:Date类内:

内联函数:

检查日期是否合法

代码语言:javascript
代码运行次数:0
复制
//检查日期是否合法的函数
bool CheckDate()
{
	if (_month < 1 || _month>12
		|| _day< 1 || _day>GetMonthDay(_year, _month))
	{
		return false;
	}

}

获取每个月的天数

代码语言:javascript
代码运行次数:0
复制
	//获取每个月的天数——该函数使用最为频繁,故直接放到类里作内联函数。
	int GetMonthDay(int year, int month)
	{
		//保证月份在正确的区间
		assert(month > 0 || month < 13);

		//把数组放到静态区
		//原因:由于频繁调用,为避免其每次进入函数都反复创建空间
		static int MonthArr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };//将第0个位置空出来


		//闰年的二月情况单独
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return 29;
		}

			return MonthArr[month];
	}

友元函数(以便全局函数(流输入输出函数)使用私有)

代码语言:javascript
代码运行次数:0
复制
	//友元函数的声明:
	// 作用:可以在类访问私有
	friend ostream& operator<<(ostream& out, const Date& d);//流输出
	friend istream& operator>>(istream& in, Date& d);//流输入
	//流输入这里是不能加const的,因为我们提取的值要写到对象d里面去

2.cpp文件:具体功能实现

运算符重载功能:比较大小

代码语言:javascript
代码运行次数:0
复制
//运算符重载功能
// operator传值注意:
// d1(对应operator)的地址,d2(对应参数列表第一个参数)的地址

//比较大小
//应学会的技巧:复用函数~
bool Date::operator > (const Date& d)
{
	//从day开始比较
	//天大就大
	if(_day > d._day)
	{
		return true;
	}
	//天相等,月大就大
	else if(_day == d._day && _month > d._month)
	{
		return true;
	}
	//天、月相等,年大就大
	else if (_day == d._day && _month == d._month && _year > d._year)
	{
		return true;
	}
	return false;
}


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

// == 的函数取反(!),就是 != 的函数
bool Date::operator != (const Date& d)
{
	return !(*this == d);
}


// d1 >= d2
//this是d1的地址,d是d2的地址
// 
// >= 重载,直接结合 > 和 = 的运算符重载函数 
bool Date::operator >= (const Date& d)
{
	//注意:此处的this是指针,改变其数值要使用*this
	//      而d是引用,改变值直接使用d
	return *this > d || *this == d;
}

// >= 的函数取反(!),就是 < 的函数
bool Date::operator < (const Date& d)
{
	return !(*this >= d);
}

// > 的函数取反(!),就是 < 的函数
bool Date::operator <= (const Date& d)
{
	return !(*this > d);
}

日期类加减

代码语言:javascript
代码运行次数:0
复制
//日期类的加减
//日期加日期无意义,日期加整型(如天数)有意义

// += 是天数直接赋值到对象,会改变对象的值,故使用引用Date&
// + 是算以后多少天的日期,不改变数值,故直接Date
Date& Date::operator += (int day)
{
	//d1 += -100, d1 = d1-100
	if (day < 0)
	{
		//d1 - (-100) = d1 + 100
		return *this -= -day;
	}
	_day += day;
	//天数大于当月天数
	while (_day > GetMonthDay(_year, _month))
	{
		//月份进一位,天数减掉当月天数
		_day -= GetMonthDay(_year,_month);
		++_month;

		//月份大于12,说明这一年过去了
		if (_month == 13)
		{
			//年份进一位,月份更新为来年一月
			_year++;
			_month = 1;
		}
	}

	return *this;
}

//此前提是已经有+= 运算符重载函数
//注意: + 是不改变对象的
Date Date::operator + (int day)
{
	//调用拷贝构造,拷贝this指向的对象
	Date tmp = *this;
	//赋值给tmp
	tmp += day;
	//返回tmp,不会改变原对象的值
	return tmp;
}

Date& Date::operator -= (int day)
{
	//d1 -= -100 ,d1 = d1 + (-100)
	if (day < 0)
	{
		//d1 + (-100) == d1 - 100; 
		return *this += -day;
	}

	//原来的天数减去要减的天数
	_day -= day;
	while (_day <= 0)
	{
		-- _month;
		if (_month == 0)
		{
			//说明到上一年12月了
			--_year;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

//原理同上 +
Date Date::operator - (int day)
{
	//拷贝构造
	Date tmp (*this);
	tmp -= day;//利用上面实现的 -=
	return tmp;
}

日期前置后置++--

代码语言:javascript
代码运行次数:0
复制
	//日期前置与后置++--

	//前置++ 返回++后的值,即直接返回改变值后的对象,用引用
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
//后置++ 返回++前的值,即用一个拷贝对象 拷贝改变值前的值返回,
Date Date::operator++(int)
{
	Date tmp(*this);//先拷贝构造出一个对象
	*this += 1;

	return tmp;//返回++以前的值
}

//原理同上
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
Date Date::operator--(int)
{
	Date tmp(*this);//先拷贝构造出一个对象
	*this -= 1;
	return tmp;//返回--以前的值
}

两个日期相减

代码语言:javascript
代码运行次数:0
复制
​
//两个日期相减
//思路:让小的日期进行++,直到走到了大的日期
//加了多少次就是多少天,不需要考虑其他的条件
int Date::operator-(const Date& d)
{
	//传入默认 d1 - d2
	Date max = *this;//默认假设d1大
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		//此时d1 - d2 是负数,故flag要变-1 避免返回负数
		max = d;
		min = *this;
		flag = -1;
	}

	//计数器count
	int count = 0;
	while (min != max)
	{
		min++;
		count++;
	}

	return count * flag;//避免返回负数
}

​

日期自定义格式流输出和输入

代码语言:javascript
代码运行次数:0
复制
​

//流输出
ostream& operator <<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "日" << d._day << "日" << endl;
}
//流输入
istream& operator >> (istream& in,Date& d)
{
	//这里要注意输入的日期可能不合法
	while (1)//用循环,直至输入合法日期可跳出循环
	{
		cout << "请输入正确的日期:" << endl;
		in >> d._year >> d._month >> d._day;

		if (d.CheckDate())
		{
			break;
		}
		else
		{
			cout << "日期非法,请重新输入" << endl;
		}
	}
	return in;
}

​

具体代码:

Date.h

代码语言:javascript
代码运行次数:0
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<assert.h>
using namespace std;

class Date
{
public:
	//友元函数的声明:
	// 作用:可以在类访问私有
	friend ostream& operator<<(ostream& out, const Date& d);//流输出
	friend istream& operator>>(istream& in, Date& d);//流输入
	//流输入这里是不能加const的,因为我们提取的值要写到对象d里面去

	
	Date(int year = 1999, int month = 1, int day = 1);
//void point (const Date* const this) const; 传参列表有隐藏的this指针
//调用是会将引用对象的地址传给this指针(if你调用的是d1.print() ,便将d1地址传过去)
	void print() const;//函数后面加const的作用如上

	//检查日期是否合法的函数
	bool CheckDate()
	{
		if (_month < 1 || _month>12
			|| _day< 1 || _day>GetMonthDay(_year, _month))
		{
			return false;
		}

	}


	//获取每个月的天数——该函数使用最为频繁,故直接放到类里作内联函数。
	int GetMonthDay(int year, int month)
	{
		//保证月份在正确的区间
		assert(month > 0 || month < 13);

		//把数组放到静态区
		//原因:由于频繁调用,为避免其每次进入函数都反复创建空间
		static int MonthArr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };//将第0个位置空出来


		//闰年的二月情况单独
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return 29;
		}

			return MonthArr[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);


//————————————————————————————————————————————————————————
//日期类的加减
//日期加日期无意义,日期加整型(如天数)有意义

// += 是天数直接赋值到对象,会改变对象的值,故使用引用Date&
// + 是算以后多少天的日期,不改变数值,故直接Date

	Date& operator += (int day);
	Date operator + (int day);

	Date& operator -= (int day);
	Date operator - (int day);

//————————————————————————————————————————————————————————
	//日期前置与后置++--
	
	//前置++ 返回++后的值,即直接返回改变值后的对象,用引用
	Date& operator++();
	//后置++ 返回++前的值,即用一个拷贝对象 拷贝改变值前的值返回,
	Date operator++(int);

	//原理同上
	Date& operator--();
	Date operator--(int);
//————————————————————————————————————————————————————————
//两个日期相减
	int operator-(const Date& d);

//————————————————————————————————————————————————————————
//流输出和流输入
	
	//即需要重载<< >>,此时重载必须为全局函数
	//若重载为成员函数,this指针默认抢占第一个形参位置,即变成 this对象 << cout
	//而我们正常应该是 cout << this对象

	//注意:由于是在全局函数,无法访问类内私有的_year _month _day
	//此时我们在Date类开头加友元函数声明这个全局函数(即流输入输出函数)

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


//流输出
ostream& operator <<(ostream& out, const Date& d);

//流输入
//流输入这里传参列表是不能加const的,因为我们提取的值要写到对象d里面去
istream& operator >>(istream& in,Date& d);

Date.cpp

代码语言:javascript
代码运行次数:0
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"

//Date:: 的作用 
// 在某个类的外面定义它的成员函数,要指定类域,否则无法知道是否是某个类的成员函数
//即不知道你_year那些是哪来的(它默认只在全局找,不特定标明他不会特地去类域找)

//为啥声明里(Date.h)有缺省值,定义(Date.cpp)没有?
// (参数列表中初始定义传入的参数为某个数值,如 int year = 10)
// 复习一下!缺省值 在声明和定义都存在时,只在声明中标明。
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

//注:Date::在函数名前加!别在返回值前加!
void Date::print()
{
	cout << _year << "-" << _month << "-" << _day << endl;
}


//————————————————————————————————————————————————————————
//运算符重载功能
// operator传值注意:
// d1(对应operator)的地址,d2(对应参数列表第一个参数)的地址

//比较大小
//应学会的技巧:复用函数~
bool Date::operator > (const Date& d)
{
	//从day开始比较
	//天大就大
	if(_day > d._day)
	{
		return true;
	}
	//天相等,月大就大
	else if(_day == d._day && _month > d._month)
	{
		return true;
	}
	//天、月相等,年大就大
	else if (_day == d._day && _month == d._month && _year > d._year)
	{
		return true;
	}
	return false;
}


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

// == 的函数取反(!),就是 != 的函数
bool Date::operator != (const Date& d)
{
	return !(*this == d);
}


// d1 >= d2
//this是d1的地址,d是d2的地址
// 
// >= 重载,直接结合 > 和 = 的运算符重载函数 
bool Date::operator >= (const Date& d)
{
	//注意:此处的this是指针,改变其数值要使用*this
	//      而d是引用,改变值直接使用d
	return *this > d || *this == d;
}

// >= 的函数取反(!),就是 < 的函数
bool Date::operator < (const Date& d)
{
	return !(*this >= d);
}

// > 的函数取反(!),就是 < 的函数
bool Date::operator <= (const Date& d)
{
	return !(*this > d);
}

//————————————————————————————————————————————————————————
//日期类的加减
//日期加日期无意义,日期加整型(如天数)有意义

// += 是天数直接赋值到对象,会改变对象的值,故使用引用Date&
// + 是算以后多少天的日期,不改变数值,故直接Date
Date& Date::operator += (int day)
{
	//d1 += -100, d1 = d1-100
	if (day < 0)
	{
		//d1 - (-100) = d1 + 100
		return *this -= -day;
	}
	_day += day;
	//天数大于当月天数
	while (_day > GetMonthDay(_year, _month))
	{
		//月份进一位,天数减掉当月天数
		_day -= GetMonthDay(_year,_month);
		++_month;

		//月份大于12,说明这一年过去了
		if (_month == 13)
		{
			//年份进一位,月份更新为来年一月
			_year++;
			_month = 1;
		}
	}

	return *this;
}

//此前提是已经有+= 运算符重载函数
//注意: + 是不改变对象的
Date Date::operator + (int day)
{
	//调用拷贝构造,拷贝this指向的对象
	Date tmp = *this;
	//赋值给tmp
	tmp += day;
	//返回tmp,不会改变原对象的值
	return tmp;
}

Date& Date::operator -= (int day)
{
	//d1 -= -100 ,d1 = d1 + (-100)
	if (day < 0)
	{
		//d1 + (-100) == d1 - 100; 
		return *this += -day;
	}

	//原来的天数减去要减的天数
	_day -= day;
	while (_day <= 0)
	{
		-- _month;
		if (_month == 0)
		{
			//说明到上一年12月了
			--_year;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

//原理同上 +
Date Date::operator - (int day)
{
	//拷贝构造
	Date tmp (*this);
	tmp -= day;//利用上面实现的 -=
	return tmp;
}


//————————————————————————————————————————————————————————
	//日期前置与后置++--

	//前置++ 返回++后的值,即直接返回改变值后的对象,用引用
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
//后置++ 返回++前的值,即用一个拷贝对象 拷贝改变值前的值返回,
Date Date::operator++(int)
{
	Date tmp(*this);//先拷贝构造出一个对象
	*this += 1;

	return tmp;//返回++以前的值
}

//原理同上
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
Date Date::operator--(int)
{
	Date tmp(*this);//先拷贝构造出一个对象
	*this -= 1;
	return tmp;//返回--以前的值
}

//————————————————————————————————————————————————————————

//两个日期相减
//思路:让小的日期进行++,直到走到了大的日期
//加了多少次就是多少天,不需要考虑其他的条件
int Date::operator-(const Date& d)
{
	//传入默认 d1 - d2
	Date max = *this;//默认假设d1大
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		//此时d1 - d2 是负数,故flag要变-1 避免返回负数
		max = d;
		min = *this;
		flag = -1;
	}

	//计数器count
	int count = 0;
	while (min != max)
	{
		min++;
		count++;
	}

	return count * flag;//避免返回负数
}

//————————————————————————————————————————————————————————

//流输出
ostream& operator <<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "日" << d._day << "日" << endl;
}
//流输入
istream& operator >> (istream& in,Date& d)
{
	//这里要注意输入的日期可能不合法
	while (1)//用循环,直至输入合法日期可跳出循环
	{
		cout << "请输入正确的日期:" << endl;
		in >> d._year >> d._month >> d._day;

		if (d.CheckDate())
		{
			break;
		}
		else
		{
			cout << "日期非法,请重新输入" << endl;
		}
	}
	return in;
}

Test.cpp

代码语言:javascript
代码运行次数:0
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
 
 
int main()
{
    //Date d1(2024, 8, 10);
    //d1.Print();//2024-8-10
    ///*d1 += 100;
    //d1.Print();*///2024-11-18
 
    //Date d2 = d1 + 100;
    //d2.Print();
    //d1.Print();//那么这里的d1就没有被改变了
    ///*int i = 1;
    //i + 100;*/
    ///*
    //如果是单纯的+的话,原先的对象是不会被改变的,但是现在我们的对象已经被改变了
    //由此可知我们在这里实现的是+=的操作符
    //*/
    //d1 += 100; 
    //d1.Print();
 
 
    //d1 -= 100;
    //d1.Print();
 
    //Date ret1=++d1;
    //d1.Print();
    //Date ret2 = d1++;
    //d1.Print();
 
    //ret1.Print();
    //ret2.Print();
    Date d1(2024, 2, 29);
    Date d2(2024, 8, 20);
    cout << d1 - d2 << endl;
    cout << d2 - d1 << endl;
 
    /*cout << d1;*/
    /*d1 << cout;*///我们只有这么写才能正确打印出来日期
    //d1对应的就是隐含的this指针,cout对应的就是后面的参数
    //但是这种写法很怪
    //那么我们是否有方法将这个进行改变呢
 
    /*
    重载<<和>>时,需要重载为全局函数
    然后我们的ostream/iostream就能放到第一个参数了
    然后第二个参数就是我们的对象了*/
    cout << d1; 
    operator<<(cout, d1);//本质
    //那么到这里我们就不支持了
    cout << d1<<d2<<endl;
    //我们这里是从左往右进行结合
    //对于cout << d1这个我们的返回值应该是cout 然后cout和d2
    //再次返回cout 和endl
 
    //所以流插入是需要返回cout的
 
    cin >> d1 >> d2;
    cout << d1 << d2 << endl;
    return 0;
}

希望对你有帮助

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实现功能:
    • 1.h文件:Date类内:
      • 内联函数:
    • 2.cpp文件:具体功能实现
  • 具体代码:
    • Date.h
    • Date.cpp
    • Test.cpp
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档