【C++】日期类

因为类和对象有点复杂,一时间不知道怎么组织语言,所以先写这个。

---------

既然决定写一个 日期 类,那就需要三个参数:

年,月,日

所以先定义出来:

class Data
{

public:

private:
	int _year;
	int _month;
	int _day;
};

里面的三个对象就不用公开,有需要可以直接在类里面操作。

------

构造函数

我们知道,有三种构造函数:

1、无参

2、缺省

3、编译器自带

这里就不适合用编译器自带的,因为编译器自带的对于内置类型(int、double...)不会做处理,所以这里用的是缺省参数。

Data(int year,int month, int day)
    {
        this->_year = year;
        this->_month = month;
        this->_day = day;
    }

为了方便阅读,所以我在这里会用this指针,可以简单理解为就是要改变的参数,假设这是d1要初始化,那this就是d1,this->_year = d1->year;

当写出这样的代码的时候,有没有一种可能,就是用户使用的时候他传来一个相对错误的日期,比方说:

不是闰年的时候传进来2 29号

一个月的第32天

公元300年

...

显然,这些是我们没有考虑到的,所以为了更合理的使用这个日期类,我们最好加一个判断条件:

如果年份太离谱,报错

如果月份日期不对,报错

但是,要如何来判断这个月份对不对呢?

可以再套一个函数:

Data(int year,int month, int day)
    {
        if (year < 1900 ||
            month < 1 ||
            month>12 ||
            day>GetMonthDay(year, month))
        {
            cout << "error" << endl;
        }
        this->_year = year;
        this->_month = month;
        this->_day = day;
    }

稍微改进一下,如果年份小于1900,那就报错,如果月份小于1,如果月份大于12,或者是

day>GetMonthDay ;

这个GetMonthDay ,是之后要实现的一个函数,来判断这个月有多少天,具体实现也挺简单的,首先要开辟一个数组,这个数组里面放上每个月的具体天数,然后根据传过去的参数来返回这个月有多少天。

这里要注意一点,别忘了判断闰年:

int GetMonthDay(int year, int month)
    {
        int MonthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 
        if (year % 4 == 0 && year % 100 != 0 ||
            year % 400 == 0)
            if (month == 2)
                return 29;    
        return MonthDayArray[month];
    }

这里要注意的一点是,最后返回日期的时候,如果创建的数组的大小是12,那返还的的应该是MonthDayArray[month-1]

连起来:

【C++】日期类_第1张图片

既然写好了构造函数,那就来用一下:

【C++】日期类_第2张图片

报错,因为2022不是闰年,所以没有29天

既然创建好了一个初始对象,那我们正好写一个打印函数,来方便我们查看里面的内容:

void printf()
    {
        cout << this->_year << " " << this->_month << " " << this->_day << endl;
    }

 很简单的函数,就不细说了。

【C++】日期类_第3张图片

可以看到,如果是之前的代码来跑这个的话,因为当时写的时候是直接打印error然后返回,所以d1里面的值都是随机值,如果我们写一个正确的值的话:

【C++】日期类_第4张图片

还是没问题的。

-----

析构函数 

写不写都可以,这里为了说明写一个简单一点的析构函数:

~Data()
    {
        this->_day = this->_month = this->_year = 0;
    }

类名前面加上一个波浪号表示这是一个析构函数,实现方式就是直接讲三个参数重制为零就好了。

------- 

拷贝构造函数

 初始化的时候,我们不止可以用单纯的的类型来初始化,还可以用一个对象来初始化另一个对象,这个操作称之为拷贝构造。

拷贝分为两种:

浅拷贝,也称之为值拷贝,它是很简单的一个字节一个字节的拷贝

对于那些int double 来说它是可以用的,但是假若开辟了一块空间,那浅拷贝的时候它会把这个指针的地址也拷贝过去,也就是说两个对象的指针指向的是同一块空间,就会出现析构两次,或者是操作一个对象另一个对象也出现对应现象的错误。

为了解决这种错误,出现了另一个,叫做:深拷贝

深拷贝就不会出现这种问题,但对于我们现在写的日期来说,浅拷贝也已经够用了。

同样,这里也是可以不写的,这里是为了示范:

Data(const Data& d)
    {
        this->_year = d._year;
        this->_month = d._month;
        this->_day = d._day;
    }

 这里要说一点,当我们传参数的时候,假若是要讲d2拷贝为d1的内容,那我们调用类函数的时候是这样的:

d2(d1);

我们传过去的参数只要一个d1,d2它是会被默认传过去的,如果在传一个d2过去就会引发错误,而我们想找d2的时候直接用this就可以了。

所以这里直接就是this->_year = d._year

【C++】日期类_第5张图片

--------

赋值运算符重载

这个就好像那些很简单的,用一个对象来赋值给另一个类型的对象,注意以下几点:

注意传参的时候只用传要赋值的那个就可以了

注意被赋值的对象跟要赋值的对象应该不一样,如果是自己赋值自己,这种行为还是报错比较好

 注意我们最后要返回这个值本身,因为语言本身支持这样:a = b = c,这种连续赋值,如果我们不返回值那这种情况就会报错

注意用引用,如果返回的单纯是一个值,返回中会有拷贝过程,所以这里用引用效率,或者说是速度会更快一点。

注意this是一个对象指针,指向的是要赋值的那个对象,所以要返回对象的时候应该先解引用。 

Data& operator=(const Data& d)
    {
        if (this == &d)
            cout << "error" << endl;
        else
        {
            this->_year = d._year;
            this->_month = d._month;
            this->_day = d._day;
        }
        return *this;
    }

【C++】日期类_第6张图片

日期+=天数

这个其实也很好解决,我们直接将天数加上去,然后进行判断,如果这个天数大于这个月该有的天数,那我们的月份就+1,然后天数-这个月的天数,如果过程中月份到了13,那就应该把月份重制为1. 

简单写一个:

Data& operator+=(int day)
    {
        this->_day += day;
        while (this->_day > GetMonthDay(this->_year, this->_month))
        {
            this->_day -= GetMonthDay(this->_year, this->_month);
            this->_month += 1;
            if (this->_month == 13)
            {
                this->_year += 1;
                this->_month = 1;
            }
        }
        return *this;
    }

 目前效果:

【C++】日期类_第7张图片

日期+天数

既然有+=,那就有+,不过这里有一点要注意:

+不一定是真的+上去,也许是在表达式里面进行的一个判断过程,所以我们不能直接用+=的思想。

这里也简单写一个:

Data& operator+(int day)
    {
        Data tmp(*this);
        tmp += day;
        return tmp;
    }

先初始画一个拷贝的值,然后对这个拷贝的值进行操作,再返回,不要对*this操作,注意注意注意。

-------

日期-=天数 

有加就有减,大体思路其实跟日期+差不多,同样是先减,然后再循环判断:

注意,先减一月,因为在上来的this->_day -= day的时候这个月已经减完了,所以要拿下个月的出来。 

Data& operator-=(int day)
    {
        this->_day -= day;
        while (this->_day < 0)
        {    
            this->_month -= 1;
            if (this->_month == 0)
            {
                this->_year--;
            }
            this->_day += GetMonthDay(this->_year, this->_month);

        }
        return *this;
    }

------- 

日期-天数

这个,就没什么好说的,如果明白了+,那-应该也明白了。

Data& operator-(int day)
    {
        Data tmp(*this);
        tmp -= (day);
        return tmp;
    }

------

>运算符重载

作为一个日期类,比较大小还是很简单的,首先比较年,如果年比较不出来大小,那就比较月,如果月比较不出来,那就比较天。

简单写一下:

bool operator>(const Data& d)
    {
        if (this->_year < d._year ||
            this->_year <= d._year&&this->_month < d._month ||
            this->_year <= d._year&&this->_month <= d._month&&this->_day <= d._day)
            return false;
        return true;
    }

效果: 

【C++】日期类_第8张图片

 ---------

==运算符

这个,算非常简单的那一种,我们直接比较对应的年月日即可:

bool operator==(const Data& d)
    {
        return this->_year == d._year&&
               this->_month == d._month&&
               this->_day == d._day;
    }

效果: 

【C++】日期类_第9张图片

----- 

 >=运算符重载

这里,>=的结果,是不是就是把我们之前写的大于和等于结合起来。

所以我们直接复用代码:

bool operator>=(const Data& d)
    {
        return *this > d||*this == d;
    }

效果: 

【C++】日期类_第10张图片

------

<运算符重载 

小于,是不是大于等于的结果取反?

所以还是直接复用代码:

bool operator<(const Data& d)
    {
        return !(*this >= d);
    }

效果: 

【C++】日期类_第11张图片

 -------

 <=运算符重载

小于等于,那不就是大于的取反吗

继续复用:

bool operator<=(const Data& d)
    {
        return !(*this>d);
    }

效果:

【C++】日期类_第12张图片

 --------

!=运算符重载

这还用说吗,等于取反:

bool operator!=(const Data&d)
    {
        return !(*this == d);
    }

效果:

【C++】日期类_第13张图片

 -----

 日期-日期 返回天数

这里有好几种方法实现,比如说:

1、年减年,月减月,日减日

2、一直加那个小的直到它们两个相等

第一种方法是很容易想到但是不容易实现的,因为要考虑到有的年月天数不一样,所以会比较麻烦,这里推荐使用第二种:

因为不能改变原有数据,所以我们先创建一个对象,让它来表示小的那个,然后循环:

int operator-(const Data& d)
    {
        Data min(*this);
        Data max(d);
        int count = 0;
        if (*this > d)
        {
            min = d;
            max = *this;
        }
        while (max != min)
        {
            count++;
            min+=1;
        }
        return count;
    }

默认小的那个是*this,大的那个是d,然后判断如果取反了就交换,再累加计算,效果:

 【C++】日期类_第14张图片

-----

前置++

这里要注意的一点是,前置++是先++,然后再算。

Data operator++()
    {
        *this += 1;
        return *this;
    }

效果:

【C++】日期类_第15张图片

----

后置++

这里要注意一点,因为是后置,所以为了区分前置,它会在参数里面默认传过去一个int,不需要接收,只是为了表明这是后置++。

注意一点,后置++是先运行完再++,所以不能直接用*this,而是用一个对象保存当前*this的值饭后,然后再++*this。

Data operator++(int)
    {
        Data tmp(*this);
        *this += 1;
        return tmp;
    }

【C++】日期类_第16张图片

可以看到第一次的时候还不相等,++完就相等了。

-----

前置-- 

跟前置++一样,直接复制过来修改一下就好:

Data operator--()
    {
        *this -= 1;
        return *this;
    }

后置--

同理:

Data operator--(int)
    {
        Data tmp(*this);
        *this -= 1;
        return tmp;
    }

【C++】日期类_第17张图片

 ---------

支持,日期类就告一段落,希望这篇文章对您有所帮助,下篇文章再见

你可能感兴趣的:(c++,开发语言,c语言)