日期类的实现

以下代码是类和对象告一段落后,通过写日期类来对类和对象的知识点完成融会贯通。同时附带对代码的改进
特别声明:这里的改进并不是自上而下的改进,而是边写边改进,所以整体的结构并不是很合理。作为学习参考并不友好。看看就行。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
        Date(int year = 1900, int mouth = 1, int day = 1)
        {
               if (year > 0 && mouth >= 1 && mouth <= 12 && day >= 1 && day <= GetMouthDay(year, mouth))
               {
                       _year = year;
                       _mouth = mouth;
                       _day = day;
               }
               else
                       cout << "不存在该日期" << endl;
        }
        Date(const Date& d)
        {
               _year = d._year;
               _mouth = d._mouth;
               _day = d._day;
        }
        int GetMouthDay(int year, int mouth)
        {
               int a[13] = { 31,31,28,31,30,31,30,31,31,30,31,30,31 };
               if (year % 4 == 0 && year % 100 != 0 && mouth == 2
                       || year % 400 == 0 && mouth == 2)
               {
                       return 29;
               }
               return a[mouth];
        }
        Date& operator=(const Date& d)
        {
               _year = d._year;
               _mouth = d._mouth;
               _day = d._day;
               return *this;
        }
        Date& operator+=(int day)
        {
               _day += day;
               while(_day > GetMouthDay(_year, _mouth))
               {
                       _day -= GetMouthDay(_year, _mouth);
                       _mouth++;
                       if (_mouth > 12)
                       {
                              _mouth -= 12;
                              _year++;
                       }
               }
               return *this;
        }
        Date operator+(int day)
        {
               int sumday = _day + day;
               int mouth = _mouth;
               int year = _year;
               while (sumday > GetMouthDay(year, mouth))
               {
                       sumday -= GetMouthDay(year, mouth);
                       mouth++;
                       if (mouth > 12)
                       {
                              mouth -= 12;
                              year++;
                       }
               }
               Date d(year, mouth, sumday);
               return d;
        }
        Date operator-(int day)
        {
               int sumday = _day - day;
               int mouth = _mouth;
               int year = _year;
               while (sumday <= 0)
               {
                       sumday += GetMouthDay(year, mouth - 1);
                         //在获取月份天数哪里将0月的位置改为12月的天数,解决0月的问题
                       mouth--;
                       if (mouth == 0)
                       {
                              mouth += 12;
                              year--;
                       }
               }
               Date d(year, mouth, sumday);
               return d;
        }
        Date& operator-=(int day)
        {
               _day -= day;
               while (_day <= 0)
               {
                       _day += GetMouthDay(_year, _mouth - 1);
                         //在获取月份天数哪里将0月的位置改为12月的天数,解决0月的问题
                       _mouth--;
                       if (_mouth == 0)
                       {
                              _mouth += 12;
                              _year--;
                       }
               }
               return *this;
        }
        Date& operator++()
        {
               _day++;
               if (_day > GetMouthDay(_year, _mouth))
               {
                       _day -= GetMouthDay(_year, _mouth);
                       _mouth++;
                       if (_mouth > 12)
                       {
                              _mouth -= 12;
                              _year++;
                       }
               }
               return *this;
        }
    //下面这个是后置++,暂时不会写,后置++此时不能有缺省值,如果加上那么调用++重载函数,前置++后置++都是不需要参数的,使用++时编译器就会不知道调用哪一个了
         /*Date operator++(int day)
        {
               _day++;
               if (_day > GetMouthDay(_year, _mouth))
               {
                       _day -= GetMouthDay(_year, _mouth);
                       _mouth++;
                       if (_mouth > 12)
                       {
                              _mouth -= 12;
                              _year++;
                       }
               }
               return *this;
        }*/
        Date& operator--()
        {
               _day--;
               if (_day <= 0)
               {
                       _day += GetMouthDay(_year, _mouth-1);
                       _mouth--;
                       if (_mouth <= 0)
                       {
                              _mouth += 12;
                              _year--;
                       }
               }
               return *this;
        }
        bool operator>(const Date& d)
        {
               if (_year > d._year)
                       return true;
               else
               {
                       if (_year == d._year && _mouth > d._mouth)
                       {
                              return true;
                       }
                       else
                       {
                              if (_mouth == d._mouth && _day > d._day)
                              {
                                      return true;
                              }
                       }
               }
               return false;
        }
        bool operator==(const Date& d)
        {
               return _year == d._year && _mouth == d._mouth && _day == d._day;
        }
        bool operator>=(const Date& d)
        {
               if (_year > d._year)
                       return true;
               else
               {
                       if (_year == d._year && _mouth > d._mouth)
                       {
                              return true;
                       }
                       else
                       {
                              if (_year == d._year && _mouth == d._mouth && _day >= d._day)
                              {
                                      return true;
                              }
                       }
               }
               return false;
        }
        bool operator<(const Date& d)
        {
               if (_year < d._year)
                       return true;
               else
               {
                       if (_year == d._year && _mouth < d._mouth)
                       {
                              return true;
                       }
                       else
                       {
                              if (_mouth == d._mouth && _day < d._day)
                              {
                                      return true;
                              }
                       }
               }
               return false;
        }
        bool operator<=(const Date& d)
        {
               if (_year < d._year)
                       return true;
               else
               {
                       if (_year == d._year && _mouth < d._mouth)
                       {
                              return true;
                       }
                       else
                       {
                              if (_year == d._year && _mouth == d._mouth && _day <= d._day)
                              {
                                      return true;
                              }
                       }
               }
               return false;
        }
        bool operator!=(const Date& d)
        {
               return !(_year == d._year && _mouth == d._mouth && _day == d._day);
        }
        int operator-(const Date& d) //计算日期之间间隔的天数,暂时不会写
        {
               
        }
        void Print()
        {
               cout << _year << "-" << _mouth << "-" << _day << endl;
        }
        ~Date() //析构函数,日期类不需要写
        {
        }
private:
        int _year;
        int _mouth;
        int _day;
};
int main()
{
        Date d1(2022, 5, 30);
        Date d2(d1);
        Date d3(2022, 1, 1);
        --d3;
        d3.Print();
        ++d3;
        d3.Print();
        cout << endl;
        d3 = d2;
        d3 += 365;
        d3.Print();
        d3 -= 365;
        d3.Print();
        cout << endl;
        Date ret = d2 + 2;
        ret.Print();
        d2.Print();
        ret = d2 - 2;
        ret.Print();
        d2.Print();
        cout << endl;
        if (d1 == d2)
        {
               cout << "==true" << endl;
        }
        d2 += 30;
        if (d2 > d1)
        {
               cout << ">true" << endl;
        }
        if (d2 >= d1)
        {
               cout << ">=true" << endl;
        }
        if (d1 < d2)
        {
               cout << "<true" << endl;
        }
        if (d1 <= d2)
        {
               cout << "<=true" << endl;
        }
        if (d1 != d2)
        {
               cout << "!=true" << endl;
        }
        cout << endl;
        d3.Print();
        d1.Print();
        d2.Print();
        cout << d1.GetMouthDay(2020, 2) << endl;
        return 0;
}
上面的代码大约300行,下面来对代码进行改进:
第一个要改进的就是整体的代码通过一个规范性的项目格式来写:
创建test.cpp,Date.h,Date.cpp
声明和定义不能分离的是内联函数,类中函数的声明和定义可以分离,只是需要一定格式。
Date.h中
#pragma once
#include<iostream>
#include<assert.h>
using std::cout; //从项目角度来看,std肯定是不会全部放出来,只将常用的放出来
using std::cin;
using std::endl;
class Date
{
public:
        Date(int year = 1900, int mouth = 1, int day = 1)
        {
               if (year > 0 && mouth >= 1 && mouth <= 12 && day >= 1 && day <= GetMouthDay(year, mouth))
               {
                       _year = year;
                       _mouth = mouth;
                       _day = day;
               }
               else
                       cout << "不存在该日期" << endl;
        }
        int GetMouthDay(int year, int mouth) //这个函数放到.cpp中比较好,这里为了防止结构混乱就不放了
        {
               assert(year >= 0 && mouth >= 1 && mouth <= 12);
               static int a[13] = { 31,31,28,31,30,31,30,31,31,30,31,30,31 };
              //前面加上static,就避免了每次调用都要开数组的问题,static存在的多线程问题是多线程写,多线程读是没有问题的。
               if (year % 4 == 0 && year % 100 != 0 && mouth == 2
                       || year % 400 == 0 && mouth == 2)
               {
                       return 29;
               }
               return a[mouth];
        }
        void Print()
        {
            cout << _year << "-" << _mouth << "-" << _day << endl;
        }
    Date operator+(int day);
    Date operator+=(int day);
    Date operator-(int day);
    Date operator-=(int day);
    int operator-(const Date& d);
    bool operator>(const Date& d);
    bool operator==(const Date& d);
    / /还可以通过内联来进行优化,但是内联不支持把声明和定义分别放在.h和.cpp中,所以直接将复用的重载函数放到类中,在类中定义的函数默认是内联函数。不进行复用的重载函数也可以考虑放到类中去。
    //注释掉的是原本不用内联优化的情况
    // bo ol operator!=(const Date& d);
    //bool operator<=(const Date& d);
    //bool operator<(const Date& d);
        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);
        }
        //这种复用不仅适用于日期类,还适用于所以需要比大小的自定义类型
         Date& operator++() //前置++和后置++的区别:参数,无参默认调用前置++,这是语法规定
        {
            *this += 1;
            return *this;
        }
        Date operator++(int) //这里的函数形参类型只能是int,只说明类型,不设置参数名代表函数形参不会使用
        {
            Date tmp(*this);
            *this += 1;
            return tmp;
        }
        Date& operator--()
        {
            *this -= 1;
            return *this;
        }
        Date operator--(int)
        {
            Date tmp(*this);
            *this -= 1;
            return tmp;
        }
private:
    int _year;
    int _mouth;
    int _day;
};
Date.cpp中
//提供一个构造函数就足够了,析构函数,拷贝构造函数,赋值重载函数 默认的就可
        bool Date::operator>(const Date& d) //声明和定义分离,定义要指定所属的类域
        {
               if (_year > d._year)
                       return true;
               else
               {
                       if (_year == d._year && _mouth > d._mouth)
                       {
                              return true;
                       }
                       else
                       {
                              if (_mouth == d._mouth && _day > d._day)
                              {
                                      return true;
                              }
                       }
               }
               return false;
        }
//完成了大于的函数运算符重载,小于之类运算符也很简单了,但是大于和小于之间的区别不大,函数逻辑高度重合,在这种情况下是可以进行复用的。只要再完成等于的运算符重载函数。
        bool Date::operator==(const Date& d)
        {
               return _year == d._year && _mouth == d._mouth && _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);
         }*/
        Date Date::operator+(int day) //注意:重载的操作符是+,不是+=,也就是说不会修改this指针指向的对象
        {
            if(day < 0)
                return *this -= -day;
            int sumday = _day + day;
            int mouth = _mouth;
            int year = _year;
            while (sumday > GetMouthDay(year, mouth))
            {
                sumday -= GetMouthDay(year, mouth);
                mouth++;
                if (mouth > 12)
                {
                    mouth -= 12;
                    year++;
                }
            }
            Date d(year, mouth, sumday);
            return d; //d是局部变量,不能引用返回
        }
        Date& Date::operator+=(int day)
        {
                //这里的逻辑和+的逻辑高度重合,也可以复用+,同理+也可以复用+=
               /*_day += day ;
                while (_day > GetMouthDay(_year, _mouth))
               {
                       _day -= GetMouthDay(_year, _mouth);
                       _mouth++;
                        if (_mouth > 12)
                       {
                              _mouth -= 12;
                              _year++;
                       }
               }
                return * this ;*/
                *this = *this + day; //这里复用了+的重载函数,也可以复用+=的重载函数,实际上,复用+=效率更高,+的重载函数中有两个拷贝构造函数(初始化,返回值),+=复用+,就会导致+=也调用了两次拷贝构造,如果是+复用+=,因为+=不需要拷贝构造,所以只需要调用+本身需要的拷贝构造函数就可以了。
                //复用的函数很短,可以设为内联函数
                return *this;
        }
        Date& Date::operator-=(int day)
        {
            if(day < 0) //针对day为负的处理
                return *this += -day;
            _day -= day;
            while (_day <= 0)
            {
                _mouth--;
                if (_mouth == 0)
                {
                    _mouth += 12;
                    _year--;
                }
                _day += GetMouthDay(_year, _mouth);
         //加天数不能放在前面,0月的问题需要解决,就算在GetMouthDay函数中,把0月代表的数改为12月代表的数也不可以。
        //因为GetMouthDay不是只服务于-=重载函数,还有其他函数要用,在其他函数中0月如果合法,会出现bug
            }
            return *this;
        }
        Date Date::operator-(int day)
        {
            Date d(*this);
            d -= day;
            return d;
        }
        int Date::operator-(const Date& d) //两个日期相差天数
        {
            Date max = *this;
            Date min = d;
            int flag = 1;
            if (*this < d)
            {
                max = d;
                min = *this;
                flag = -1;
            }
            int day = 0;
            while (max != min)
            {
                day++;
                min++;
            }
            return day * flag;
        }
test.cpp中
#include"Date.h"
void testDate1()
{
    Date d1(2022, 5, 30);
    Date d2(2023, 3, 31);
    Date d3(2022, 5, 30);
    cout << (d1 < d2) << endl;
    //d1<d3不加括号会报错,因为流插入操作符优先级很高,比<号高。流插入也是一个运算符重载后面会讲到。
    cout << (d1 <= d2) << endl;
    cout << (d1 == d3) << endl;
    cout << (d1 > d2) << endl;
    cout << (d1 >= d2) << endl;
}
void testDate2()
{
    Date d1(2022, 5, 30);
    Date d2 = d1 + 365;
     //这里调用了+的运算符重载函数和拷贝构造,虽然使用了=,但是拷贝构造就是用一个同类型的对象去初始化另一个对象,不管是Date d2 = d1;还是Date d2(d1);调用的都是拷贝构造函数,初始化就是在创建时赋值。如果是Date d2;d2 = d1;就是赋值重载函数了
    //还有一点,很多日期类为返回值的情况下,日期类参数都要加上const,否则会报错,原因在于返回值中途要拷贝,变成const修饰的类型,比如d2 = d1 + 365,d1+ 365的返回值类型为Date,返回的是返回值的拷贝,返回的日期类已经被const修饰了,此时引用给d2,如果参数前面没有const,就会发生权限放大问题,编译器会报错。当然部分编译器会优化掉这个问题。
    d2.Print();
    d2 += 365;
    d2.Print();
    d1.Print();
}
void testDate3()
{
    d2 -= -100; //有时会出现这种情况,这就要对-=部分进行处理了
    d2.Print();
}
void testDate4()
{
    Date d2(2022, 3, 1);
    Date ret = --d2;
    ret.Print();
    d2.Print();
    ret = ++d2;
    ret.Print();
    d2.Print();
}
void testDate5()
{
    Date d1(2022, 5, 28);
    Date d2(2026, 5, 28);
    cout << (d1 - d2) << endl;
    cout << (d2 - d1) << endl;
}
int main()
{
    testDate1();
    testDate2();
    testDate3();
    testDate4();
    testDate5();
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值