模拟实现Date类

日期类是很常用的一个类,我们要模仿实现的就是日常生活中会用到的一些功能。
首先给出Date类的头文件:

class Date
{
    friend std::ostream& operator<<(std::ostream& _cout, const Date& d);
    friend std::istream& operator>>(std::istream& _cin, Date& d);
public:
    Date(int year = 1970, int month = 1, int day = 1);
    ~Date();
    Date(const Date& d);
    int getYear() const;
    int getMonth() const;
    int getDay() const;
    Date& operator=(const Date& d);
    Date operator+(int days) const;
    Date& operator+=(int days);
    Date operator-(int days) const;
    Date& operator-=(int days);
    int operator-(const Date& d) const;
    Date& operator++();
    Date operator++(int);
    Date& operator--();
    Date operator--(int);
    Date* operator&();
    const Date* operator&() 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;
    bool operator!=(const Date& d) const; 
private:
    bool isLeapYear() const;
    int getDayInMonth() const;
    int _year;
    int _month;
    int _day;
};

下面我们来一一实现它们:

//构造函数
//使用初始化参数列表,为成员变量一一赋值即可。
//当初始化完成后,用assert语句判断成员变量的合法性。
//如果不合法,返回异常。
Date::Date(int year, int month, int day)
    :_year(year)
    ,_month(month)
    ,_day(day)
{
    assert(this->_month < 13 && this->_month > 0
        && this->_day > 0 && this->_day < getDayInMonth());
}


//析构函数
//将成员变量赋值为0
Date::~Date()
{
    _year = 0;
    _month = 0;
    _day = 0;
}


//拷贝构造函数
//这里的形参只能用引用类型。
//如果直接用的是对象类型,那么就会在传参的时候创建一个形参d,
//而d是用实参拷贝构造的,这样就会一直循环下去。
Date::Date(const Date& d)
    :_year(d._year)
     ,_month(d._month)
     ,_day(d._day)
{}

//返回年份
int Date::getYear() const
{
    return this->_year;
}

//返回月份
int Date::getMonth() const
{
    return this->_month;
}

//返回日期
int Date::getDay() const
{
    return this->_day;
}

//赋值运算符重载
//当 d 不是当前对象时,将d的成员变量的值,依次赋给当前对象的成员变量。
//并且返回当前对象的引用。
//由于这里当前对象的生命周期比函数长,因此可以直接返回当前对象的引用。
//省去了创建临时变量返回的步骤,提高了效率。
Date& Date::operator=(const Date& d)
{
    if (this != &d) {
        this->_year = d._year;
        this->_month = d._month;
        this->_day = d._day;
    }
    return *this;
}

//判断年份是否是闰年
//在Date类外,判断是否是闰年,可以由使用者自行判断。
//这里的作用是为了辅助实现其他功能,因此直接定义为私有,对外不可见。
bool Date::isLeapYear() const
{
    return (this->_year % 400 == 0) || ((this->_year % 4 == 0) && (this->_year % 100 != 0));
}


//判断日期的合法性
//用来检测日期的合法性,确保日期是正确的。
//需要注意的就只有,当是闰年时,二月日期为29天。否则,为28天。
int Date::getDayInMonth() const
{
    int daynumber[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (this->isLeapYear()) {
        daynumber[1] = 29;
    }
    return daynumber[this->_month - 1];
}



//+运算符重载
//实现的原理为:
//先将days全部加在成员变量_day上面,
//用.getDayInMonth()函数判断日期的合法性,
//当日期不正确时,从_day中减去本月的天数,将月份增加一月,
//一直循环,直到日期合法时,跳出循环,并且将计算完的对象返回。

//可以理解为:传进来一个总天数days,从当前日期往前走,每走一个月,那么从总日期中减去这个月的天数。
//然后所处的月份加一,然后从新的一月的第一天开始走。如果走完了一年,那么月份变为一月,年份加一。

//因为 + 运算符并不会 影响当前对象本身,所以因该将结果保存在临时对象中,
//又因为临时对象是创建在栈上的,所以函数运行完之后会销毁,
//因此不能返回引用,所以返回的是创建的临时对象的值。
Date Date::operator+(int days) const
{
    Date temp(*this); 
    if (days < 0) {
        return temp - (-days);
    }
    temp._day += days;
    while(temp._day > temp.getDayInMonth()) {        //日期不合法 
        temp._day -= temp.getDayInMonth();
        temp._month++;
        if (temp._month > 12) {
            temp._year++;
            temp._month = 1;
        }
    }
    return temp;
}

//+=运算符重载
//+=运算符会影响当前对象,所以直接在函数中,将 + 运算符计算的结果赋值给当前对象
//然后返回引用即可
Date& Date::operator+=(int days)
{
    (*this) = (*this) + days;
    return *this;
}


//-运算符重载
//原理同上面+运算符,只是日期是倒着走
//实现的原理为:
//先用成员变量_day减去days
//当_day < 1 时,说明日期不合法。
//当日期不合法时,将月份减少一月,给_day加上上月的天数,说明往前退了一个月。
//一直循环,直到日期合法时,跳出循环,并且将计算完的对象返回。
//需要注意的是,在计算的时候,由于是往前退一个月,所以应该是先减去月份,再加上月份对应的日期,
//或者是先加上上月的日期,然后再减去月份。
Date Date::operator-(int days) const
{
    Date temp(*this);
    if (days < 0) {
        return temp + (-days);
    }
    temp._day -= days;
    while(temp._day < 1) {
        temp._month--;
        if (temp._month < 1) {
            temp._year--;
            temp._month = 12;
        }
        temp._day += temp.getDayInMonth();
    }
    return temp;
}


//-=运算符重载
//原来相同,不做过多解释
Date& Date::operator-=(int days)
{
    (*this) = (*this) - days;
    return *this;
}

//&运算符重载
Date* Date::operator&()
{
    return this;
}

//&运算符重载   针对const 对象
const Date* Date::operator&() const
{
    return this;
}

//<<运算符重载
//我们都知道,类的成员函数第一个参数为隐含的 this 指针。
//那么对于 << 运算符如果直接重载,重载后,cout输出流就变为了第二个参数,
//而默认的 << 中,cout输出流应该为第一个参数,
//如果使用 cout << a 的形式调用,结果肯定是不对的。
//所以我们在类外进行操作符重载,然后定义为类的友元函数即可
std::ostream& operator<<(std::ostream& _cout, const Date& d)
{
    _cout<< d._year<< "-"<< d._month<< "-"<< d._day;
    return _cout;
}


//>>运算符重载
std::istream& operator>>(std::istream& _cin, Date& d)
{
    _cin>> d._year>> d._month>> d._day;
    return _cin;
}

//前置++运算符重载
//只需要对当前对象 + 1 然后返回当前对象即可
Date& Date::operator++()
{
    (*this) += 1;
    return (*this);
}

//后置++运算符重载
//函数中形参仅仅是用于与前置++构成重载
//后置++ 是 执行完当前语句后才进行++操作,
//所以我们应该先将当前对象保存起来,等当前对象++完成之后,
//再返回之前保存的值,返回值不返回引用的原因为:
//临时变量为栈上元素,函数结束后,会销毁掉
Date Date::operator++(int)
{
    Date temp(*this);
    (*this) += 1;
    return temp;
}

//前置--运算符重载
Date& Date::operator--()
{
    (*this) -= 1;
    return (*this);
}

//后置++运算符重载
Date Date::operator--(int)
{
    Date temp(*this);
    (*this) -= 1;
    return temp;
}

//-运算符重载
//用两个临时对象maxxdate 和 mindate 分别保存 d 和 当前对象中的 大日期 和 小日期
//写一个循环,让小日期加一个天数 当两个日期相等时,返回加的日期即可。
int Date::operator-(const Date& d) const
{
    int ret = 0;
    Date mindate;
    Date maxdate;
    if ((*this) == d) {
        return 0;
    }
    mindate = (*this) < d ? (*this) : d;
    maxdate = (*this) > d ? (*this) : d;
    while(1) {
        if (mindate + ret == maxdate) {
            break;
        }
        ++ret;
    }
    return ret;
}

//>运算符重载
//只需要判断对应成员变量的大小即可
bool Date::operator>(const Date& d) const
{
    return (this->_year > d._year)
        || (this->_year == d._year && this->_month > d._month)
        || (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->_year < d._year)
        || (this->_year == d._year && this->_month < d._month)
        || (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->_year == d._year 
        && this->_month == d._month 
        && this->_day == d._day;
}

//!=运算符重载
bool Date::operator!=(const Date& d) const
{
    return this->_year != d._year 
        || this->_month != d._month
        || this->_day != d._day;
}

最后附上代码地址:Mmmmmmi

以上即为本篇全部内容,不足之处还望指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值