基于j2ee的网站开发设计开题报告/视频号的链接在哪
文章目录
- 日期类的实现
- 函数实现
- 重载`==`
- 重载`<`
- 构造函数
- 重载`<=` `>` `>=` `!=`
- 重载`+=` `+` `-=` `-`天数
- 重载`++` `--`
- 重载`-`(计算日期间隔天数)
- 完整代码
- .h
- .cpp
日期类的实现
日期类的实现主要是练习运算符重载,只要是对于日期的计算有意义的运算符都应该重载。
注:本篇文章的日期只考虑公元后的。
函数实现
在中篇我们已经实现了==
和<
的重载:
重载==
比较两个日期是否相同
//.cpp
bool Date::operator==(const Date& d) const
{return _year == d._year&& _month == d._month&& _day == d._day;
}
重载<
判断左值日期是否在右值日期的前面
//.cpp
bool Date::operator<(const Date& d) const
{return ((_year < d._year)|| (_year == d._year && _month < d._month)|| (_year == d._year && _month == d._month && _day < d._day));
}
构造函数
构造函数应该对用户传进来的日期初始化进行检查
为此,我们首先要判断年月日是否在合法的范围,要判断day
的范围,需要GetMonthDay
函数获得这个月的天数,同时还要用isLeapYear
判断是否是闰年,因为isLeapYear
函数较短,所以可以直接写在类里面作为内联。
//.h
bool isLeapYear(int year)
{return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
//.cpp
int Date::GetMonthDay(int year, int month)
{assert(year >= 1 && month >= 1 && month <= 12);static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && isLeapYear(year))return 29;elsereturn monthDayArray[month];
}Date::Date(int year, int month, int day)
{if (year >= 1&& month <= 12 && month >= 1&& day >= 1 && day <= GetMonthDay(year, month)){_year = year;_month = month;_day = day;}else{cout << "日期非法" << endl;}
}
重载<=
>
>=
!=
我们已经写好了<
和==
的重载,建议直接复用这两个来实现
bool operator<=(const Date& d) const
{return *this < d || *this == d;
}
重载>
复用<=
的重载即可
bool operator>(const Date& d) const
{return !(*this <= d);
}
建议复用<
,可以少调用一个函数
bool operator>(const Date& d) const
{return d < *this;
}
重载>=
复用<
的重载即可
bool operator>=(const Date& d) const
{return !(*this < d);
}
复用<=
也可以,但是多调用一个函数
bool operator>=(const Date& d) const
{return d <= *this;
}
重载!=
复用==
bool operator!=(const Date& d) const
{return !(*this == d);
}
因为上面4个函数都比较短小,所以建议直接定义到类里面。
重载+=
+
-=
-
天数
由于+=是直接在原对象上+,所以我们先实现+=
重载+=
让一个日期对象+=天数。
思路是直接把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++;_month = 1;}}return *this;
}
👆:如果有人传入了负数的day
呢?
传入负数的day
,_day -= day
有可能小于1,也进不去下面的while循环进行处理,最终导致结果错误。当然-=
也面临同样的问题,
注意到+=一个负数就是-=这个负数的相反数,我们接下来实现-=
,然后让它们相互复用即可。
重载+
复用+=
,并且不能改变原对象,
这里就拷贝构造一个中间对象ret
,返回ret
必须传值返回,因为ret
出作用域会被销毁。
Date Date::operator+(int day) const
{Date ret(*this);ret += day;return ret;
}
不建议先写+
的重载,然后重载+=
的时候复用+
,因为+
肯定是需要拷贝构造的,如果+=
复用了+
,那么+=
也要调用拷贝构造,影响效率。
重载-=
-
同上,先实现-=
,-
直接复用-=
_day -= day
,如果_day不合法,则需要向前借位。
Date& Date::operator-=(int day)
{if (day < 0)return *this += -day;_day -= day;while (_day < 1){_month--;if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;
}Date Date::operator-(int day) const
{Date ret(*this);ret -= day;return ret;
}
重载++
--
前置++
和后置++
都是单操作数,它们的重载要如何区分呢?
要区分就需要构成函数重载,C++语法规定,增加一个int
类型额外参数的是后置++
(注意:额外参数必须是int
类型)
Date& operator++() //前置++
{*this += 1;return *this;
}
Date operator++(int) //后置++
{Date tmp(*this);*this += 1;return tmp;
}
Date& operator--() //前置--
{*this -= 1;return *this;
}
Date operator--(int) //后置--
{Date tmp(*this);*this -= 1;return tmp;
}
调用的时候++d
等价于d.operator++()
,d++
等价于d.operator++(0)
,编译器会自动传入一个额外参数表示调用后置++。这个参数本身没有意义,所以形参部分可以省略变量名,只写int
小知识:通过++和–的重载我们可以发现,前置的效率高一些,因为后置多了两个拷贝构造。
重载-
(计算日期间隔天数)
我们再重载一个-
,只不过这里是日期减日期,表示两个日期间隔天数。
int Date::operator-(const Date& d) const
{int flag;Date max, min;if (*this > d){max = *this;min = d;flag = 1;}else{max = d;min = *this;flag = -1;}int n = 0;while (min != max){++n;++min;}return n * flag;
}
👆:先看左右操作数哪个更大,并用flag控制正负号,让小日期一直++到大日期,统计的次数即为两个日期的间隔天数。
完整代码
.h
#pragma once
#include <iostream>
#include <cassert>
using std::cout;
using std::cin;
using std::endl;class Date
{
public:bool isLeapYear(int year){return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;}int GetMonthDay(int year, int month);Date(int year = 1, int month = 1, int day = 1);void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}bool operator==(const Date& d) const;bool operator<(const Date& d) const;bool operator<=(const Date& d) const{return *this < d || *this == d;}bool operator>(const Date& d) const{return d < *this;}bool operator>=(const Date& d) const{return !(*this < d);}bool operator!=(const Date& d) const{return !(*this == d);}Date& operator+=(int day);Date operator+(int day) const;Date& operator-=(int day);Date operator-(int day) const;Date& operator++() //前置++{*this += 1;return *this;}Date operator++(int) //后置++{Date tmp(*this);*this += 1;return tmp;}Date& operator--() //前置--{*this -= 1;return *this;}Date operator--(int) //后置--{Date tmp(*this);*this -= 1;return tmp;}int operator-(const Date& d) const;private:int _year;int _month;int _day;
};
.cpp
#include "Date.h"int Date::GetMonthDay(int year, int month)
{assert(year >= 1 && month >= 1 && month <= 12);static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && isLeapYear(year))return 29;elsereturn monthDayArray[month];
}Date::Date(int year, int month, int day)
{if (year >= 1&& month <= 12 && month >= 1&& day >= 1 && day <= GetMonthDay(year, month)){_year = year;_month = month;_day = day;}else{cout << "日期非法" << endl;}
}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 ((_year < d._year)|| (_year == d._year && _month < d._month)|| (_year == d._year && _month == d._month && _day < d._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++;_month = 1;}}return *this;
}Date Date::operator+(int day) const
{Date ret(*this);ret += day;return ret;
}Date& Date::operator-=(int day)
{if (day < 0)return *this += -day;_day -= day;while (_day < 1){_month--;if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;
}Date Date::operator-(int day) const
{Date ret(*this);ret -= day;return ret;
}int Date::operator-(const Date& d) const
{int flag;Date max, min;if (*this > d){max = *this;min = d;flag = 1;}else{max = d;min = *this;flag = -1;}int n = 0;while (min != max){++n;++min;}return n * flag;
}
还有流插入<<
和流提取>>
的重载本篇文章未实现。因为涉及到友元,我们将在下篇作为例子实现。