C++?Date類的具體使用(構(gòu)建,重載等)
寫在前面
我們今天寫一個Date類作為C++初始類的結(jié)尾,這里涉及到的知識,里面有很多運算符的重載,包括權(quán)限的問題,我們都已經(jīng)分享過了,所以大家不用擔心,這里算是一個總結(jié)吧.我這里用的的是Linux環(huán)境,主要是鍛煉自己的能力.
成果
我們要完成一個什么樣的Date類呢,大家可以搜一下時間計算器,我們就完成他們的功能,比如說加減300天或者看看兩個日期之間的天數(shù),這就是我們要完成的任務.
準備工作
這里我們用三個文件來寫,分別是Date.h,Date.cpp,test.cpp.我們先把初始工作給做好了,我們先把框架各搭出來,后面要的功能一一補足.
Date.h
#include <iostream> #include <assert.h> using std::cout; using std::endl; class Date { public: Date(int year = 1900, int month = 1, int day = 1); //析構(gòu)函數(shù) ~Date(); // 拷貝構(gòu)造 Date(const Date& d); private: int _year; int _month; int _day; };
Date.cpp
#include "Date.h" Date::Date(int year, int month, int day) { } ~Date() { } Date(const Date& d) { }
test.cpp
#include "Date.h" int main() { return 0; }
構(gòu)造函數(shù)
我們先來寫一下日期類的構(gòu)造函數(shù),本來這是沒有多少問題的,但是我們知道一個月的天數(shù)是有限制的,而且還有閏年于平年之分,這就考慮的有點難度了,但是這要符合我們的客觀規(guī)律.我們先來把思路捋順.
第一點 我們把年月份給對象,其中肯定都是大于0的整數(shù),這個是毋庸置疑的,第二步,我們要判斷這一年是平年還是閏年,第三步,要判斷給的月數(shù)的對應的天數(shù)是否合理.
我們分別用方法來完成自己的要求.
判斷平年 or 閏年
這個很簡單,記得去類里面聲明這個方法.
bool Date::isLeap(int year) { assert(year > 0); return (year % 4 == 0 && year %100 != 0) || year % 400 == 0; }
判斷天數(shù)是否合理
我們都知道每一月分都有固定的天數(shù),而且月份是肯定小于13的,
int Date::isLegitimate(int year,int month) { static int monthDay[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; assert(month > 0 && month < 13); assert(day > 0); //判斷閏年 && 而且 月份是 2 月 if(isLeap(year) && month == 2) { return 29; } return monthDay[month]; }
我來解釋一下我們定義數(shù)組的時候為什么用的是 static ? 我們知道,這是一個函數(shù),也就是說函數(shù)棧幀會在結(jié)束后銷毀,但是我們可能多次調(diào)用這個函數(shù),為了避免多次開辟和銷毀該數(shù)組的空間,這里直接用static修飾得了.
寫好構(gòu)造函數(shù)
到這里我們已經(jīng)寫好了的構(gòu)造函數(shù),沒必要在說其他了.
Date::Date(int year = 1900, int month = 1, int day = 1) { if(year > 0 && month > 0 && month <13 && day <= isLegitimate(year,month)) { _year = year; _month = month; _day = day; } else { // 這里應該拋出一個異常 // 現(xiàn)在我還不太會 暫時用 assert代替 assert(NULL); } }
析構(gòu)函數(shù) & 拷貝構(gòu)造
說實話,這兩個函數(shù)我們不用寫,主要是我們沒有使用動態(tài)開辟空間,都是一些基本的內(nèi)容,編譯器生成的已經(jīng)完全夠了,這里大家看看就行了.
由于這兩個函數(shù)都不大,這里就聲明成內(nèi)聯(lián)函數(shù)函數(shù)吧,在類內(nèi)實現(xiàn).
// 析構(gòu)函數(shù) inline ~Date() { _year = 0; _month = 0; _day = 0; } // 拷貝構(gòu)造 inline Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; }
運算符重載
某種意義上,運算符重載才是我們今天的大頭,我們不是重載所有的運算符,而是要重載那些符合我們邏輯的,例如一個日期加上一個日期就沒有什么意義,這里就不會重載它.
邏輯運算符的重載
這個基本的邏輯運算符都有意義,這里我們一一給大家重載出來,同時也驗證一下.
重載 ==
這個很好寫,如果日期的年月日都相等,那么這兩個日期一定相等.
bool Date:: operator==(const Date& d) const { return _year == d._year && _month == d._month && _day == d._day; }
重載 >
如果一個日期的年數(shù)比較大,那么它一定更大,如果相等,就比較月份,如果月份還相等,那就比較天數(shù),這就是這個的原理.
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); }
重載 >=
只要我們完成了上面的兩個,后面就可以直接調(diào)用它們了,避免重復造輪子.
bool Date::operator>=(const Date& d) const { return *this > d || *this == d; }
重載 <
從這里開始,我就不演示結(jié)果了,都是和之前的一樣.
我們知道,小于的對立面就是大于大于等于
bool Date::operator<(const Date& d) const { return !(*this >= d); }
重載 <=
小于等于的對立面是大于,我們已經(jīng)實現(xiàn)了.
bool Date::operator<=(const Date& d) const { return !(*this > d); }
重載 !=
這個更加簡單,不等于不就是等于的對立面嗎
bool Date::operator!=(const Date& d) const { return !(*this == d); }
算數(shù)運算符的重載
上面的都挺簡單的,這里算數(shù)運算符我們要重載的有加法,等于,減法,前置和后置++…有一定的額難度,尤其是加法和減法.
重載 =
等于的重載基本來說對于我們是沒有任何問題的,但是有一點是需要我們注意的,無論是C語言還是C++都是支持連等的,也就是a = b = c,那就意味者我們們重載等于的時候是要有返回值的.
Date& Date::operator=(const Date& d) { // 避免 重復 if(this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this; }
重載 +
說實話,加號還是比較簡單的,我們首先要把給的天數(shù)判斷一下,假如要是小于零,就去調(diào)用重載的減號,后面我會實現(xiàn)減法的,這里先考慮好.
那么我們該如何把這個邏輯給完善好呢?第一步,就是把給的天數(shù)直接加到_day上面,如果還沒有超過當前月最大的天數(shù),我們就直接返回這個日期就可以了,否則就把日期減去當前月最大的天數(shù),當前月加一,注意,這里要明白,如果當前月是12月,我們直接把月份置為1,年加上一,這里要注意一點東西 ,我們不修改原來的日期
我們可以分為三種情況,每一個我都列出來,本質(zhì)上是一個循環(huán).
- 2022-2-1 + 12 _day = 13 < 2月份的最大值,返回 2022-2-13
- 2022-4-30 + 7 _day = 37 > 4月份最大值, _day-=30 月份+1 = 5,我們發(fā)現(xiàn) _day = 7 < 5月份的最大值,循環(huán)結(jié)束
- 2022-12-31 + 2 _day = 33 > 12月份最大值, _day-=31,月份是12,直接置為1, _year加1,繼續(xù)循環(huán),判斷 _day = 2是不是滿足循環(huán)條件
Date Date::operator+(const int day) const { //先判斷 day 是否是 小于零 if(day < 0) { return (*this)-(-day); } // 第一步 來個第三方 不要修改原來的 Date ret(*this); // 這是拷貝構(gòu)造 ret._day += day; while(ret._day > ret.isLegitimate(ret._year,ret._month)) { ret._day -= ret.isLegitimate(ret._year,ret._month); if(ret._month == 12) { ret._month = 1; ret._year += 1; } else { ret._month += 1; } } return ret; }
重載+=
我們直接復用+和=就可以了,這里沒什么可以分享的.
Date& Date::operator+=(const int day) { //判斷 是不是 小于 0 if(day < 0) { return (*this) = (*this) - (-day); } return (*this) = (*this) + day; }
重載 -
我們們這里要重載加號的的話,需要分為兩種共請情況
- 參數(shù) 是 天數(shù)
- 參數(shù) 是 日期
很榮幸,C++是支持重載的,我們也按照步驟來.
參數(shù)是天數(shù)
這個就是計算一個日期減去多少天得到另一個日期,也是比較簡單的,我們要考慮一些之情況,這里小于零的情況就不解釋了,主要看我們的思路是什么.
我們首先把_day減去day,判斷是不是小于0,小于的話,就從上個月的日期天數(shù)加到 _day上,直到它它大于0,這里要注意的是,如果我們的月份恰好是12,那么上一個月是1月份,并且年也要減1
Date Date::operator-(const int day) const { // day 的大小 if(day < 0) { return (*this) + (-day); } Date ret(*this); ret._day -= day; //開始判斷 ret._day while(ret._day <= 0) { // 找上一個月的 if(ret._month == 1) { ret._month = 12; ret._year -= 1; } else { ret._month -= 1; } int days = ret.isLegitimate(ret._year,ret._month); ret._day += days; } return ret; }
參數(shù)是日期
這個更加簡單的,我們計算的是兩個日期之間差的天數(shù),我們可以復用前面的方法.
還是先說下思路,我們想,如果一個較小的日期每次加一,直到加到和較大的日期完全一樣,我們計算加的次數(shù)是不是就可以完成這個操作符的重載了.那么我們?nèi)绾我玫礁〉娜掌?是不是要比較,然后交換這里是不用的,我們用一個標志位.我們假設日期A比日期B小,標志位flag = 1,如果不成立,我們把flag編程-1,隨即我們用日期A加上flag,進行循環(huán).
int Date:: operator-(const Date& d) { // 給一個 數(shù) 來計數(shù) int count = 0; int flag = 1; // 不能修改原來的,這里用一個第三方 Date ret(*this); if(ret > d) { flag = -1; } while(ret != d) { ret += flag; count++; } return flag*count; }
重載-=
這個我們復用減號就可以了,就不解釋了.
Date& Date::operator-=(const int day) { if(day < 0) { return(*this) = (*this)+(-day); } return (*this) = (*this) - day; }
重載++
我們這就不解釋前置和后置的區(qū)別了,上一個博客分享過了,直接開始吧.
前置
前置是不需要帶參數(shù)的.
Date& Date::operator++() { *this += 1; return *this; }
后置
需要帶一個int類型的參數(shù)
Date Date::operator++(int day) { Date ret(*this); *this += 1; return ret; }
重載 –
既然我們都把減法給重載了,那這我們直接復用就可以了
前置
不帶參數(shù)
Date& Date::operator--() { *this -= 1; return *this; }
后置
帶上參數(shù)
Date Date:: operator--(int day) { Date ret(*this); *this -= 1; return ret; }
重載流提取 & 流插入
這原理我們已經(jīng)分享過了,這里就不加贅述了,記得使用友元
>>
std::istream& operator>>(std::istream& in, Date& d) { in >> d._year >> d._month >> d._day; return in; }
<<
std::ostream& operator<<(std::ostream& out, Date& d) { out << d._year << "-" << d._month << "-" << d._day; return out; }
到此這篇關(guān)于C++ Date類的具體使用(構(gòu)建,重載等)的文章就介紹到這了,更多相關(guān)C++ Date類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++多重繼承引發(fā)的重復調(diào)用問題與解決方法
這篇文章主要介紹了C++多重繼承引發(fā)的重復調(diào)用問題與解決方法,結(jié)合具體實例形式分析了C++多重調(diào)用中的重復調(diào)用問題及相應的解決方法,需要的朋友可以參考下2018-05-05