山河日月镌刻璀璨初心
八载春秋写就举世华章
目录
日期类Date的实现
构造函数
拷贝构造函数
获取月份天数的函数
日期类的检查
日期类的打印
运算符重载日期类的比较
运算符重载>
运算符重载==
运算符的复用
日期加天数
日期减天数
编辑 运算符重载+
运算符重载-
日期类的前置++
日期类的后置++
日期类的前置--
日期类的后置--
日期减日期
整体代码的实现
契子✨
我们学了那么久的 C++ 类与对象,是时候写个小项目练练手了~
先提前总结一下今天要用到的知识点(日期类Date 最基本的东西):
私有成员,构造函数,拷贝构造函数,析构函数(编译器默认生成),赋值运算符重载
日期类Date的实现
首先登场的就是我们日期类的成员变量
//私有成员变量:
private:
int _year;
int _month;
int _day;
构造函数
//构造函数
Date::Date(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
拷贝构造函数
//拷贝构造函数
Date::Date(const Date& d)
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
}
获取月份天数的函数
<1>因为这个函数后面要反复调用,所以为了节省空间我们最好写成内联的形式
在C++中放在 public 内的就是内联
<2>如果 MonthDayArray 数组没有转化成静态,也就是每调用一次都要进行空间开辟和释放
效率不高,所以我们加 static 进行修饰转换成静态变量
int GetMonthDay(int year, int month)
{
static int MonthDayArray[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (this->_month == 2 && (this->_year % 4 == 0 && this->_year % 100 != 0) || (this->_year % 400 == 0))
{
return 29;
}
else
{
return MonthDayArray[this->_month];
}
}
日期类的检查
bool Date::CheckDate()
{
if (this->_month < 1 || this->_month>12 || this->_day<0 || this->_day>GetMonthDay(this->_year, this->_month))
{
return false;
}
else
{
return true;
}
}
日期类的打印
void Date::Print()
{
cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl;
if (!CheckDate())
{
cout << "非法日期!" << endl;
}
}
运算符重载日期类的比较
运算符重载>
bool Date::operator>(const Date& d)
{
if (this->_year > d._year)
{
return true;
}
else
{
if (this->_year == d._year)
{
if (this->_month > d._month)
{
return true;
}
else
{
if (this->_month == d._month)
{
return this->_day > d._day;
}
}
}
}
return false;
}
写好了我们就来测试一下,最好写一点就测一点(不要写代码两分钟,改错两小时)
void Test()
{
Date d1(2024, 4, 15);
Date d2(2024, 5, 1);
if (d1 > d2)
{
cout << "d1>d2" << endl;
}
else
{
cout << "d1<d2" << endl;
}
system("pause");
}
事实证明我们的程序是没有任何问题的
运算符重载==
bool Date::operator==(const Date& d)
{
return this->_year == d._year && this->_month == d._month && this->_day == d._day;
}
void Test()
{
Date d1(2024, 4, 15);
Date d2(2024, 5, 1);
Date d3(2024, 5, 1);
if (d1 == d2)
{
cout << "d1 == d2" << endl;
}
else
{
cout << "d1 != d2" << endl;
}
if (d2 == d3)
{
cout << "d2 == d3" << endl;
}
else
{
cout << "d2 != d3" << endl;
}
system("pause");
}
写完 > 和 == 的运算符我们写其他的运算符重载就可以直接复用啦
运算符的复用
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) || (*this == d);
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
我在这里就不一一进行测试了
日期加天数
<1>首先用当前的天数加上跨越的天数 |
<2>如果大于当月的最大天数则进入循环进行 消日增月 |
<3>如果月份超过了 12 则 消月增年 |
<4>当天数合法则退出循环并返回 *this |
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= -day;
}
this->_day += day;
while (this->_day > GetMonthDay(this->_year, this->_month))
{
this->_day -= GetMonthDay(this->_year, this->_month);
++this->_month;
if (this->_month == 13)
{
++this->_year;
this->_month = 1;
}
}
return *this;
}
代码测试 -- 网上做好的日期计算器(来看看我们写的是否相符)
void Test()
{
Date d1(2024, 4, 16);
d1.Print();
d1 += 100;
d1.Print();
system("pause");
}
事实证明我们的程序是没有任何问题的
我们再来测试一个:
日期减天数
<1>首先用当前的天数减去跨越的天数 |
<2>如果大于或等于 0 则进入循环进行 消月增日 |
<3>如果月份不够减,就 消年增月 |
<4>当天数合法则退出循环并返回 *this |
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
this->_day -= day;
while (_day <= 0)
{
--this->_month;
if (this->_month == 0)
{
this->_month = 12;
--this->_year;
}
this->_day += GetMonthDay(this->_year, this->_month);
}
return *this;
}
这个和加天数类似,就不进行讲解了
注意:因为总有一些人会在加天数中写负值,在减天数中写正值,所以我们要一开始要判断
运算符重载+
Date Date::operator+(int day)
{
Date tmp = *this;
tmp += day;
return tmp;
}
我们这里需要使用拷贝构造,我们要返回的是加后的值,但是并不希望当前日期变化
所以我们使用拷贝函数将当前日期拷贝一份进行加的操作
注意:Date tmp = *this 和 Date tmp(*this) 是等价的,都是拷贝构造
注意:
运算符重载+,内部创建tmp拷贝构造,值返回拷贝构造(传值调用),2 次调用拷贝构造
日期减天数+=,内部没有拷贝构造
所以综上还是写+=调用拷贝构造的次数少,效率更高
运算符重载-
Date Date::operator-(int day)
{
Date tmp = *this;
tmp -= day;
return tmp;
}
日期类的前置++
this 指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& Date::operator++()
{
*this += 1;
return *this;
}
日期类的后置++
注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将 this 保存一份
而 tmp 是临时对象,因此只能以值的方式返回,不能返回引用
Date Date::operator++(int)
{
Date tmp = *this;
*this += 1;
return tmp;
}
因为前置和后置的命名会冲突,所以 C++ 将 后置++ 的参数设为 int 进行区分
但调用函数时该参数不用传递(参数变量可以不写),编译器自动传递
日期类的前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
日期类的后置--
Date Date::operator--(int)
{
Date tmp = *this;
*this -= 1;
return tmp;
}
日期减日期
✨日期减日期返回的是天数,所以我们采用的方法很简单就是用计数器去记录两者相差的天数
int Date::operator-(const Date& d)
{
int flag = 1;
Date max = *this;
Date min = d;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int count = 0;
while (min != max)
{
++min;
++count;
}
return count * flag;
}
代码测试:
写一个大家最关心的问题~
void Test()
{
Date d1(2024, 4, 16);
Date d2(2024, 5, 1);
cout << "距离五一放假还有 " << d2 - d1 << " 天" << endl;
system("pause");
}
再来测试一个:
整体代码的实现
Date.h⭐
#include<iostream> #include<assert.h> using namespace std; class Date { public: Date(int year = 2024, int month = 5, int day = 1); Date(const Date& d); int GetMonthDay(int year, int month) { static int MonthDayArray[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (this->_month == 2 && (this->_year % 4 == 0 && this->_year % 100 != 0) || (this->_year % 400 == 0)) { return 29; } else { return MonthDayArray[this->_month]; } } //判断日期是否正确 bool CheckDate(); //打印日期 void Print(); //运算符重载 bool operator>(const Date& d)const; bool operator==(const Date& d)const; bool operator >= (const Date& d)const; bool operator < (const Date& d)const; bool operator <= (const Date& d)const; bool operator != (const Date& d)const; Date& operator+=(int day); Date operator+(int day)const; Date operator-(int day)const; Date& operator-=(int day); // 前置++ Date& operator++(); // 后置++ Date operator++(int); // 后置-- Date operator--(int); // 前置-- Date& operator--(); //计算两个日期之差 int operator-(const Date& d)const; private: int _year; int _month; int _day; };
Date.cpp⭐
#include"Date.h" //构造函数 Date::Date(int year, int month, int day) { this->_year = year; this->_month = month; this->_day = day; } //拷贝构造函数 Date::Date(const Date& d) { this->_year = d._year; this->_month = d._month; this->_day = d._day; } //判断日期是否正确 bool Date::CheckDate() { if (this->_month < 1 || this->_month>12 || this->_day<0 || this->_day>GetMonthDay(this->_year, this->_month)) { return false; } else { return true; } } //打印日期 void Date::Print() { cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl; if (!CheckDate()) { cout << "非法日期!" << endl; } } bool Date::operator>(const Date& d)const { if (this->_year > d._year) { return true; } else { if (this->_year == d._year) { if (this->_month > d._month) { return true; } else { if (this->_month == d._month) { return this->_day > d._day; } } } } return false; } bool Date::operator==(const Date& d)const { return this->_year == d._year && this->_month == d._month && this->_day == d._day; } bool Date::operator>=(const Date& d)const { return (*this > d) || (*this == d); } bool Date::operator<(const Date& d)const { return !(*this > d); } bool Date::operator<=(const Date& d)const { return !(*this > d) || (*this == d); } bool Date::operator!=(const Date& d)const { return !(*this == d); } Date& Date::operator+=(int day) { if (day < 0) { return *this -= -day; } this->_day += day; while (this->_day > GetMonthDay(this->_year, this->_month)) { this->_day -= GetMonthDay(this->_year, this->_month); ++this->_month; if (this->_month == 13) { ++this->_year; this->_month = 1; } } return *this; } Date Date::operator+(int day)const { Date tmp = *this; tmp += day; return tmp; } Date& Date::operator-=(int day) { if (day < 0) { return *this += -day; } this->_day -= day; while (_day <= 0) { --this->_month; if (this->_month == 0) { this->_month = 12; --this->_year; } this->_day += GetMonthDay(this->_year, this->_month); } return *this; } Date Date::operator-(int day)const { 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) const { int flag = 1; Date max = *this; Date min = d; if (*this < d) { max = d; min = *this; flag = -1; } int count = 0; while (min != max) { ++min; ++count; } return count * flag; }
Test.cpp⭐
#include"Date.h" void Test() { Date d1(2024, 4, 16); Date d2(2024, 5, 1); cout << "距离五一放假还有 " << d2 - d1 << " 天" << endl; system("pause"); } int main() { Test(); return 0; }
🌤️注意:我上面有些函数加了const修饰,限制了隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改
举个栗子~
我们知道类的成员函数都有一个 隐藏的 this 指针
bool Date::operator>(const Date& d) const
按语法可以写成这个
bool Date::operator>(Date *this,const Date& d) const
等价于下面这个式子
bool Date::operator>(const Date *this,const Date& d)
我们发现加了 const 限制了成员函数的 this 指针:
表明在该成员函数中不能对类的任何成员进行修改,起到一定的代码安全维护性
先介绍到这里啦~
有不对的地方请指出💞