前言:
本篇我们要实现一个日期类,其实非常困难,因为要对日期实现加加减减,也就是要对前面的知识做出一个巩固。
头文件:
因为要判断闰年,所以我们要去创建一个数组。也就是创建一个返回每月日期的函数。因为闰年要单独判断,所以
这里有一个知识点,就是直接声明在类中的函数,都是内联函数。
//直接定义在类里面,默认是inline(内联)
//频繁调用
int getMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
//默认平年
static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
//判断闰年,先判断2月再判断闰年
if (month == 2 && year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
{
return 29;
}
else
{
return monthDayArray[month];
}
return monthDayArray[month];
}
日期相加:
日期类相加是有意义的,我们相当于对未来几天的计算。
我们完成日期类,先写+=,之后完善+可以复用+=。
复用+=比较好,因为复用+的话会先调用拷贝构造,之后返回的时候再调用一次拷贝构造。
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= -day;
}
_day += day;
//这里是while循环
while (_day > getMonthDay(_year, _month))
{
_day -= getMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
return *this;
}
Date Date::operator+(int day) const
{
Date tmp = *this;//拷贝构造
//再写一遍就会很冗余,所以直接调用+=
tmp += day;
return tmp;
//此时不能使用引用返回,因为会销毁tmp
}
日期相减:
这也是有意义的。
日期类相减我们需要注意的事项: 函数重载和运算符重载没有关系。
多个同一运算符可以构成函数重载。
日期++:
此时如果我们要实现前置++和后置++的运算符重载,为了区分,后置++需要强制加上int形参。
//++d1
Date& operator++();
//d1++
//为了区分,构成重载
//强行给后置++ 增加了一个int形参
Date& operator++(int);
打印日期:
自动识别类型本质是因为流插入重载构成函数重载。
因为可以直接打印内置类型,但是此时我们想直接打印引用类型,我们就需要自己去写。
operator<< 想重载为成员函数,可以,但是用起来不符合正常逻辑,不建议这样使用,建议重载为全局函数。所以我们使其成为全局函数。
void operator<<(ostream& out, Date d)
{
//out就是cout
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}
但是此时私有的问题又出现了,我们可以利用友元……看图:
本质就是实参顺序,但是此时:
cout << d1 << d2;
会报错,所以该怎么办呢?因为流插入结合性是从左往右,所以要返回ostream&才行。
ostream& operator<<(ostream& out, Date d);
这样就支持链式输出。
传入const常量:
如果我们定义一个常量的日期类,如果直接调用里面的函数,会报错。
void Date::Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
因为权限可以缩小,所以对于比较的函数最好都加上const(也就是没有改变*this的函数)。
+=不能加const,但是+可以,因为+=相当于修改了*this,但是+不会。
总结:
没啥总结,就是有空再写一遍,这里给出全部代码:
Date.h头文件:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
//设置友元函数声明
//流插入初始为全局函数
friend ostream& operator<<(ostream& out, const Date d);
//流提取
friend istream& operator>>(istream& in, Date& d);
public:
//缺省函数在定义的时候给
Date(int year = 1900, int month = 1, int day = 1);
void Print() const;
//直接定义在类里面,默认是inline(内联)
//频繁调用
int getMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
//默认平年
static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
//判断闰年,先判断2月再判断闰年
if (month == 2 && year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
{
return 29;
}
else
{
return monthDayArray[month];
}
return monthDayArray[month];
}
//检查日期合法性
bool CheckDate();
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);
// d1 - 100
Date operator-(int day) const;
// d1 - d2
int operator-(const Date& d) const;
//++d1 -> d1.operator++()
Date& operator++();
//d1++ -> d1.operator++(1)
//为了区分,构成重载
//强行给后置++ 增加了一个int形参
Date operator++(int);
Date& operator--();
Date operator--(int);
//流插入
//不建议,因为Date* this 占据了第一个参数位置,使用 d << cout 不符合习惯
//void operator<<(ostream& out);//必须传入引用
private:
int _year;
int _month;
int _day;
};
//流插入初始为全局函数
ostream& operator<<(ostream& out, const Date d);
//流提取
istream& operator>>(istream& in, Date& d);
Date.cpp源文件:
#include"Date.h"
//检查日期合法性
bool Date::CheckDate()
{
if (_month < 1 || _month > 12
|| _day < 1 || _day > getMonthDay(_year, _month))
{
return false;
}
return true;
}
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
cout << "日期非法" << endl;
}
}
void Date::Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
bool Date::operator<(const Date& d) const
{
if (_year < d._year) {
return true;
}
else if (_year == d._year)
{
if (_month < d._month)
{
return true;
}
else if (_month == d._month)
{
return _day < d._day;
}
}
return false;
}
bool Date::operator==(const Date& d) const
{
return _year == d._year
&& _month == d._month
&& _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);
}
bool Date::operator!=(const Date& d) const
{
return !(*this == d);
}
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= -day;
}
_day += day;
//这里是while循环
while (_day > getMonthDay(_year, _month))
{
_day -= getMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
return *this;
}
Date Date::operator+(int day) const
{
Date tmp = *this;//拷贝构造
//再写一遍就会很冗余,所以直接调用+=
tmp += day;
return tmp;
//此时不能使用引用返回,因为会销毁tmp
}
//Date Date::operator+(int day)
//{
//
// Date tmp = *this;//拷贝构造
// tmp._day += day;
// //这里是while循环
// while (tmp._day > getMonthDay(tmp._year, tmp._month))
// {
// tmp._day -= getMonthDay(tmp._year, tmp._month);
// tmp._month++;
// if (tmp._month == 13)
// {
// tmp._year++;
// tmp._month = 1;
// }
// }
//
// return tmp;
// //此时不能使用引用返回,因为会销毁tmp
//}
//
//Date& Date::operator+=(int day)
//{
// *this = *this + day;
// return *this;
//}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
//小于等于0都需要继续
_month--;
if (_month == 0)
{
_month = 12;
_year--;
}
//借上个月的天数
_day += getMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day) const
{
Date tmp = *this;
tmp -= day;
return tmp;
}
//++d1 -> d1.operator++()
Date& Date::operator++()
{
*this += 1;
return *this;
}
//d1++ -> d1.operator++(1)
//为了区分,构成重载
//强行给后置++ 增加了一个int形参 (这个形参可加可不加)
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
{
//两个日期相减, 让小的加到大的为止
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
++min;
++n;
}
return n * flag;
}
流插入
//void Date::operator<<(ostream& out)
//{
// //out就是cout
// out << _year << "年" << _month << "月" << _day << "日" << endl;
//}
ostream& operator<<(ostream& out, const Date d)
{
//out就是cout
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
//流提取
istream& operator>>(istream& in, Date& d) {
cout << "请一次输入年月日:" << endl;
in >> d._year >> d._month >> d._day;
if (!d.CheckDate())
{
cout << "日期非法" << endl;
}
return in;
}
test.cpp源文件:
using namespace std;
#include"Date.h"
void TestDate1()
{
Date d1(2024, 4, 14);
Date d2 = d1 + 5000;
d1.Print();
d2.Print();
d1 += 5000;
d1.Print();
cout << endl;
Date d3(2024, 4, 14);
Date d4 = d3 - 5000;
d3.Print();
d4.Print();
d3 -= 5000;
d3.Print();
Date d5(2024, 4, 14);
d5 += -5000;
d5.Print();
}
void TestDate2()
{
Date d1(2024, 4, 14);
Date d2 = ++d1;
d1.Print();
d2.Print();
Date d3 = d1++;
d3.Print();
d1.Print();
}
void TestDate3()
{
Date d1(2024, 4, 25);
Date d2(2034, 4, 25);
int n = d1 - d2;
cout << n << endl;
}
void TestDate4()
{
Date d1(2024, 4, 25);
Date d2(2034, 4, 25);
//d1.operator<<(cout);
//cout << d1;
//d1 << cout;//要这样写
}
void TestDate5()
{
Date d1(2024, 4, 25);
Date d2(2034, 4, 25);
cout << d1;
cout << d1 << d2;
cin >> d2;
d2.Print();
}
void TestDate6()
{
const Date d1(1024, 4, 27);
//这里相当于权限放大
d1.Print();
}
int main()
{
//TestDate2();
//TestDate3();
//TestDate4();
//TestDate5();
TestDate6();
return 0;
}