参照正规项目的写法,我们分成三个文件:
我们主要实现Date.h和Date.cpp,test.cpp读者可以实际需要自行实现
Date.h
#pragma once
#include
//正规的项目写法中,只展开几个常用的函数,不展开整个命名空间
using std::cout;
using std::endl;
using std::cin;
//本类中成员变量都是内置类型,因此析构,拷贝构造,赋值重载都可以不用写
class Date
{
public:
//1.构造函数
Date(int year, int month , int day );
//2.打印
void Print() const;
//3.重载+=
Date& operator+=(int day);
//4.重载+
Date operator+(int day);
//5.重载-=
Date& operator-=(int day);
//6.重载-(日期减int)
Date operator-(int day);
//7.重载前置++与后置++
Date& operator++();
Date operator++(int);
//8.重载前置--与后置--
Date& operator--();
Date operator--(int);
//9.重载各比较运算符
bool operator>(const Date& d);
bool operator==(const Date& d) const;
bool operator>=(const Date& d);
bool operator!=(const Date& d);
bool operator<(const Date& d);
bool operator<=(const Date& d);
//10.重载-(日期减日期)
int operator-(const Date& d);
private:
int _year;
int _month;
int _day;
};
Date.cpp
先编写一个提取每月天数的函数GetMonthDay,这在后面的多个函数中都有调用,故设计成内联。内联函数不支持定义和声明分离,故Date.h中没有声明该函数
#include "Date.h"
//每生成一个对象就要调用一次,故设置成内联
inline int GetMonthDay(int year,int month)
{
//第一个给0是为了然后给月份和数组下标一一对应
static int dayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = dayArray[month];
//对于闰年的二月特殊处理
//对month的判断要写到前面
if (month == 2 && (year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
{
day = 29;
}
return day;
}
1.构造函数
Date::Date(int _year, int _month, int _day)
{
//先检查日期的合法性(假设都表示公元后)
if (_year >= 0 && (_month > 0 && _month <= 12) && (_day > 0 && _day <= GetMonthDay(_year, _month)))
{
this->_year = _year;
this->_month = _month;
this->_day = _day;
}
else
{
cout << "非法日期" << endl;
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
}
2.打印
void Date::Print() const
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
这里先插一句:C++类常成员函数的写法:
返回类型 类名::函数名(变量列表) const
const对象不能调用非const成员函数,非const对象可以调用const成员函数
为为了让const对象以及非const对象都能调用Print函数,因此设计成const函数
3.重载+=
+=可以在原本对象上操作,因此返回类型设计成引用,返回 *this
Date& Date::operator+=(int day)
{
_day += day;
//如果天数不合法就要不断循环,直至合法
while (_day > GetMonthDay(_year, _month))
{
//循环体完成进位
_day -= GetMonthDay(_year, _month);
++_month;
if (_month > 12)
{
_year += 1;
_month = 1;
}
}
return *this;
}
4.重载+
有两种实现方式
(1)直接写
//返回的是临时变量,返回类型不能填引用
Date Date::operator+(int day)
{
Date temp(*this);//调用拷贝构造函数实现初始化
temp._day+= day;
while (temp._day > GetMonthDay(temp._year, temp._month))
{
temp._day -= GetMonthDay(temp._year, temp._month);
temp._month++;
if (temp._month > 12)
{
temp._year += 1;
temp._month = 1;
}
}
return temp;
}
(2)采取复用
巧用复用很重要,复用可以帮助我们很大程度地精简代码
Date Date::operator+(int day)
{
Date temp(*this);//注意这里的初始化方式
//复用重载的+=
temp += day;
return temp;//临时变量不能返回
5.重载-=
Date& Date::operator-=(int day)
{
_day -= day;
while (_day <= 0)
{
//循环体内部完成借位
--_month;
if (_month == 0)
{
_year -= 1;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
6.重载 -
与+一样,重载-也有两种写法
(1)不复用
Date Date::operator-(int day)
{
Date temp(*this);
temp._day -= day;
while (temp._day <= 0)
{
--temp._month;
if (temp._month == 0)
{
temp._year -= 1;
temp._month = 12;
}
temp._day = GetMonthDay(_year, _month);
}
return temp;
}
(2)采取复用
Date Date::operator-(int day)
{
Date temp(*this);
temp -= day;
return temp;
}
7.重载前置++与后置++
重载前置++和后置++是一个重难点。
前置++和后置++都完成了++,不同的地方是:返回值不一样。前置++返回++之后的对象,返回Date& ; 后置++返回++之后的对象,返回Date。但单单返回类型不一样不能实现函数重载,因此我们给两个函数不同的参数列表
前置++:Date& operator++()
后置++:Date operator++(int)
后置++中的int没有实际意义,不需要给实参
//1、前置++
Date& Date::operator++()
{
(*this)._day += 1;
return *this;
}
//2.后置++
Date Date::operator++(int)
{
Date temp(*this);
(*this)._day += 1;
return temp;
}
8.重载前置–与后置–
与++类似:
//1.前置--
Date& Date::operator--()
{
(*this)._day -= 1;
return *this;
}
//2.后置--
Date Date::operator--(int)
{
Date temp(*this);
(*this)._day -= 1;
return temp;
}
9.重载各比较运算符
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)
{
if (this->_day > d._day)
{
return true;
}
}
}
//所有大于的情况均已罗列完毕
return false;
}
//如果不小心把==写成了=,加const可以很快地检查出来
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)
{
return *this > d || *this == d;
}
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);
}
10.重载-(日期减日期)
//注意:千万不要直接两者相减,这样分类讨论太麻烦了
//先判断大小,再让小的不断++,直到小的与大的相等为止
int Date::operator-(const Date& d)
{
//先假设*this是较大的那个,如果不对就交换
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;
}