个人主页: :✨✨✨初阶牛✨✨✨
推荐专栏1: C语言初阶
推荐专栏2: C语言进阶
个人信条: 知行合一
本篇简介:>:为了更好的理解C++
类和对象的知识,我们可以动手实现一下C++
的一个简单的日期类,完成相应的函数,更好的帮助我们理解类和对象.
金句分享:
✨无人问津也好,技不如人也罢✨
✨试着冷静下来,做自己该做的事!✨
这是我们需要实现的日期类的接口声明,我们需要的是在Date.cpp
文件中实现函数的定义.
class Date
{
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month);
//打印日期类函数
void Print();
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
// 拷贝构造函数
Date(const Date& d);
// 赋值运算符重载
Date& operator=(const Date& d);
// 析构函数
~Date();
// 日期+=天数
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);
private:
int _year;
int _month;
int _day;
};
声明:(在Date
类中)
//Date.h
// 全缺省的构造函数
Date(int year = 2023, int month = 1, int day = 1);
定义:
//Date.cpp
Date::Date(int year , int month, int day)
{
_year = year;
_month = month;
_day = day;
//这里也就体现出了,成员变量前面'_'的好处,方便与参数区分
}
这里需要注意的是,缺省参数应该在声明处给出,定义时不能有缺省参数,在C++
入门章节牛牛有提到过原理.
使用场景:
Date d1(2023, 4, 26);
Date d2(d1);//使用已存在的对象去初始化另一个对象,被称为拷贝构造
定义:
//Date.cpp
// 拷贝构造函数
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
注意使用引用传参.
放在以前,牛牛实现获取天数的函数可能会用一个很长的Switch case
语句,然后返回每一个天数的时间.
如今,牛牛发现,除了闰年时2
月是29
天以外,其他时候,每个月的时间是不变的,我们可以使用数组将每个月的天数存起来.
int Date::GetMonthDay(int year, int month)
{
int day[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))//如果是闰年,且是2月
{
day[2] = 29;
}
return day[month];
}
这里需要注意的是判断条件month == 2
要放在前面
((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
放在后面,因为前面的判断条件很好判断,后面的比较复杂,这样可以提高效率.
注意:
参数const Date& d
const
一方面保证右操作数不会被修改,即防止函数写反了功能.
例如:参照错误写法.
d1=d2,结果是将d2修改成了d1,偷鸡不成蚀把米.
Date&
传引用就不会调用拷贝构造函数去传参,减少拷贝,提高效率.
//运算符重载
Date& Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
//错误写法
Date& Date::operator=(Date& d)
{
d._year=_year;
d._month=_month;
d._day=_day;
return *this;
}
需要注意的是,如果month
往后推一位后为13
,则应当将month
设置为1
,并且year++
.
代码实现:
// 日期+=天数
Date& Date:: operator+=(int day)
{
if (day < 0)//不知道使用者会不会调皮传过来负数
{
return *this -= -day;//调用"-="的运算符重载
}
_day += day;
while (_day > GetMonthDay(_year, _month))//如果超过当月天数
{
_day -= GetMonthDay(_year, _month);//通过调用GetMonthDay函数获取当月天数
_month++;
if (_month > 12)//月数超过12,则开始下一年
{
_month = 1;
_year++;
}
}
return *this;
}
与日期+=
天数不同,日期+天数
要求该日期本身没有改变,而是返回日期+天数后的日期
此时,我们需要创建一个临时Date
类ret
,将增加的天数
与ret
进行计算,最后返回ret
对象.
// 日期+天数
Date Date:: operator+(int day)
{
if (day < 0)
{
return *this -= -day;//调用"-="的运算符重载
}
Date ret;//创建临时对象
ret._day += day;
while (ret._day > GetMonthDay(_year, _month))//如果超过当月天数
{
ret._day -= GetMonthDay(_year, _month);
ret._month++;
if (ret._month > 12)
{
ret._month = 1;
ret._year++;
}
}
return ret;
}
示例:2023年7月28日-100天
// 日期-=天数
Date& Date:: operator-=(int day)
{
if (day < 0)
{
return *this += -day;//调用"+="的运算符重载
}
_day -= day;
while (_day <= 0)//如果是负数
{
_month--;
if (_month <= 0)
{
_month = 12;
_year--;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
到了这里,我想日期-天数
的实现应该比较简单,牛牛就不多介绍了.
// 日期-天数
Date Date::operator-(int day)
{
if (day < 0)
{
*this -= day;//调用"-="的运算符重载
}
Date ret;
ret._day -= day;
while (ret._day <= 0)//如果是负数
{
ret._day += GetMonthDay(_year, _month-1);//+上个月的总天数
ret._month--;
if (ret._month <=0)
{
ret._month = 12;
ret._year--;
}
}
return ret;
}
日期-日期
怎么计算?
例如:
2023年7月28号距离2024年1月1号还有几天?
如果对应的年月日进行想减,然后还需要计算是那些年有那些天,月数又有几天,那可就太麻烦了吧.
所以我们直接先判断两个日期的大小,选择用较小的日期,对齐进行++
操作,直到与较大的相等,统计++
了多少天,这样是不是就很简单了?
步骤:
++
并统计,直到与较大者相等.// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
//小的日期一直++,加到和大的日期一样时,加了多少次就差多少天
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)//如果是左操作数小,则应当是负数
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)//用n统计相差多少天
{
++min;
++n;
}
return n * flag;
}
前置++
与后置++
实现的时候有一个很尴尬的问题,因为前置++和后置++都是单目运算符,即只有一个操作数,那么为了实现他们两个函数能够重载,则只能在后置++
处添加一个int
类型的参数.
这个参数用户在使用时不需要传递,编译器会自动传递,本质是为了让前置++和后置++进行函数重载.
前置++
是返回+1之后的结果,并且this是指向对象本身的,所以我们可以使用传引用返回,减少拷贝,提高效率.
后置++
是返回+1之前的值,并且对象最终还需要被修改,所以我们需要创建一个临时对象用于记录+1前对象的日期大小.除此之外,因为临时变量是在局部定义的,所以我们必须传值返回,不能传引用返回.
// 前置++
Date& Date:: operator++()
{
_day +=1;
while (_day > GetMonthDay(_year, _month))//如果超过当月天数
{
_day -= GetMonthDay(_year, _month);//则减去当月的天数
//月份向后推一个月
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
return *this;
}
// 后置++
Date Date::operator++(int)//这个参数为了个与前置++构成函数重载,调用的时候不需要传参.
{
Date tmp = *this;//要保存++前日期的大小.
_day += 1;
while (_day > GetMonthDay(_year, _month))//如果超过当月天数
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
return tmp;
}
学了前置++与后置++,这里也是类似的,需要注意的是,+上月的天数.
// 前置--
Date& Date::operator--()
{
_day -= 1;
while (_day <= 0)//如果是负数
{
_day += GetMonthDay(_year, _month - 1);//+上个月的总天数
_month--;
if (_month <= 0)
{
_month = 12;
_year--;
}
}
return *this;
}
// 后置--
Date Date::operator--(int)
{
Date tmp = *this;
_day -= 1;
while (_day <= 0)//如果是负数
{
_day += GetMonthDay(_year, _month - 1);//+上个月的总天数
_month--;
if (_month <= 0)
{
_month = 12;
_year--;
}
}
return tmp;
}
比较运算符重载我不多介绍了,没有什么难度.
需要学习的是,可以使用已经实现的>和"=="去复用实现剩下的其他运算符
bool Date::operator>(const Date& d)
{
if (_year > d._year)//如果年大
{
return true;
}
{
if (_year == d._year)
{
if (_month > d._month)//年相同,月大
{
return true;
}
else
{
if (_day > d._day)//入如果年月相同,日大
{
return true;
}
return false;//月小,或者日小和相等
}
}
return false;//如果年小
}
}
// ==运算符重载
bool Date::operator==(const Date& d)
{
if (_year == d._year&&
_month== d._month&&
_day==d._day
)
{
return true;
}
return false;
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{
if (*this > d|| *this == d)
{
return true;
}
return false;
}
// <运算符重载
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);
}
日期类就简单实现到这里了,友友们下次见,总代码,可以去我的资源处下载源代码哦.