C++實(shí)現(xiàn)日期類(lèi)的示例詳解
一、獲取某年某月的天數(shù)
1.在實(shí)現(xiàn)日期類(lèi)的過(guò)程中,日期加減天數(shù)的應(yīng)用場(chǎng)景一定會(huì)頻繁使用到這個(gè)函數(shù)接口,因?yàn)榧訙p天數(shù)會(huì)使得月份發(fā)生變化,可能增月或減月,這個(gè)時(shí)候就需要在day上面扣除或增加當(dāng)年當(dāng)月的天數(shù),所以這個(gè)接口非常的重要。
2.為了方便獲取到某年某月的天數(shù),我們將數(shù)組大小設(shè)置為13,以便月份能夠和數(shù)組中的下標(biāo)對(duì)應(yīng)上,并且我們將數(shù)組設(shè)置為靜態(tài),就不需要考慮每次調(diào)用函數(shù)建立棧幀后重新給數(shù)組分配空間的事情了,因?yàn)閿?shù)組一直被存放在靜態(tài)區(qū)。
3.四年一閏,百年不閏,四百年一閏,閏年或平年會(huì)影響2月份的天數(shù),所以我們要將這種情況單拉出來(lái)進(jìn)行處理分析。
int GetMonthDay(int year, int month) { static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) { return 29; } else { return monthDayArray[month]; } }
二、Date的默認(rèn)成員函數(shù)(全缺省的默認(rèn)構(gòu)造)
1.編譯器默認(rèn)生成的構(gòu)造函數(shù)不會(huì)處理內(nèi)置類(lèi)型,所以我們需要自己去寫(xiě)構(gòu)造函數(shù),非常推薦大家使用全缺省的構(gòu)造函數(shù),編譯器對(duì)自定義類(lèi)型會(huì)自動(dòng)調(diào)用該類(lèi)類(lèi)型的默認(rèn)構(gòu)造。
2.由于Date類(lèi)的成員變量都是內(nèi)置類(lèi)型,所以析構(gòu)函數(shù)不需要我們自己寫(xiě),因?yàn)闆](méi)有資源的申請(qǐng)。并且拷貝構(gòu)造和賦值重載也不需要寫(xiě),因?yàn)镈ate類(lèi)不涉及深拷貝的問(wèn)題,僅僅使用淺拷貝就夠了。
3.至于取地址重載和const對(duì)象取地址重載,本身就不需要我們寫(xiě)。
除非你不想讓別人通過(guò)取地址符號(hào)&來(lái)拿到實(shí)例化對(duì)象的地址,那可以返回nullptr,來(lái)屏蔽別人通過(guò)&拿到對(duì)象地址,但極大概率沒(méi)人這么做。
Date(int year = 1, int month = 1, int day = 1) { _year = year; _month = month; _day = day; // 檢查日期是否合法 if (!(year >= 1&& (month >= 1 && month <= 12)&& (day >= 1 && day <= GetMonthDay(year, month)))) { cout << "非法日期" << endl; } }
三、運(yùn)算符重載
1.+ =、+、- =、-
1.實(shí)現(xiàn)+ =或 - =之后,就不需要實(shí)現(xiàn)+ -的重載了,我們可以調(diào)用之前實(shí)現(xiàn)過(guò)的成員函數(shù),需要注意的是形參day有可能是負(fù)數(shù),對(duì)于這種情況可以將其交給+=或-=對(duì)方來(lái)處理這種情況,因?yàn)檫@兩個(gè)運(yùn)算符正好是反過(guò)來(lái)的,可以處理對(duì)方day為負(fù)數(shù)的時(shí)候的情況。
2.+=實(shí)現(xiàn)的思路就是,實(shí)現(xiàn)一個(gè)循環(huán),直到天數(shù)回到該月的正常天數(shù)為止,在循環(huán)內(nèi)部要做的就是進(jìn)月和進(jìn)年,讓天數(shù)不斷減去本月天數(shù),直到恢復(fù)本月正常天數(shù)時(shí),循環(huán)結(jié)束,返回對(duì)象本身即可。
3.-=實(shí)現(xiàn)的思路就是,實(shí)現(xiàn)一個(gè)循環(huán),直到天數(shù)變?yōu)檎龜?shù)為止,在循環(huán)內(nèi)部要做的就是借月和借年,讓天數(shù)不斷加上上一個(gè)月份的天數(shù),直到恢復(fù)正數(shù)為止,循環(huán)結(jié)束,返回對(duì)象本身。
Date& Date::operator+=(int day) { if (day < 0) { return *this -= abs(day); } _day += day; while (_day > GetMonthDay(_year, _month)) { _day -= GetMonthDay(_year, _month); ++_month; if (_month == 13) { _month = 1; ++_year; } } return *this; } Date Date::operator+(int day) { Date ret(*this); ret += day; return ret; } Date& Date::operator-=(int day) { if (day < 0) { return *this += abs(day); } _day -= day; while (_day <= 0) { --_month; if (_month == 0) { _month = 12; --_year; } _day += GetMonthDay(_year, _month); } return *this; } Date Date::operator-(int day) { Date ret(*this); ret -= day; return ret; }
2.==、!=、>、>=、<、<=
1.下面這些比較運(yùn)算符的重載應(yīng)該是非常簡(jiǎn)單的了,只需要實(shí)現(xiàn)一半的運(yùn)算符重載即可,剩余運(yùn)算符利用反邏輯操作符!即可輕松實(shí)現(xiàn)。
bool Date::operator==(const Date& d)const { return _year == d._year && _month == d._month && _day == d._day; } bool Date::operator>(const Date& d) const { if (_year > d._year) { return true; } else if (_year == d._year && _month >> d._month) { return true; } else if (_year == d._year && _month == d._month && _day > d._day) { return true; } return false; } bool Date::operator>=(const Date& d) const { return *this > d || *this == d; } bool Date::operator<=(const Date& d) const { return !(*this > d); } bool Date::operator<(const Date& d) const { return !(*this >= d); } bool Date::operator!=(const Date& d) const { return !(*this == d); }
3.前置++、–、后置++、–
1.實(shí)現(xiàn)前置和后置的區(qū)別就是,一個(gè)返回臨時(shí)對(duì)象,一個(gè)返回對(duì)象本身,在實(shí)現(xiàn)+=和-=以及+ -這些運(yùn)算符重載之后,自增或自減運(yùn)算符的重載非常簡(jiǎn)單了,也是直接套用即可。
Date& Date::operator++() { return *this += 1; } Date Date::operator++(int) { Date ret(*this); *this += 1; return ret; } Date& Date::operator--() { return *this -= 1; } Date Date::operator--(int) { Date ret(*this); *this -= 1; return ret; }
4.<<流插入、>>流提?。▋?nèi)聯(lián)的<<、>>重載函數(shù))
1.流插入和流提取不適用于在類(lèi)內(nèi)部實(shí)現(xiàn),因?yàn)殡[含的this指針會(huì)先搶到第一個(gè)參數(shù)位置,而我們又習(xí)慣將cout作為左操作數(shù)使用,這就產(chǎn)生了沖突,所以我們需要將重載放到全局位置,并且我們很可能頻繁使用這兩個(gè)重載,所以最好搞成內(nèi)聯(lián)函數(shù)。
2.起始流插入和流提取的重載非常簡(jiǎn)單,本質(zhì)上就是利用了庫(kù)中實(shí)現(xiàn)的類(lèi)的實(shí)例化對(duì)象cin和cout,他們完全支持輸出編譯器的內(nèi)置類(lèi)型,而所有的自定義類(lèi)型實(shí)際上都是內(nèi)置類(lèi)型堆砌而成,我們只需要在重載中將對(duì)象的內(nèi)置類(lèi)型一個(gè)個(gè)的輸出即可,這就是對(duì)象的流插入和流提取的本質(zhì)思想。
inline ostream& operator<<(ostream& out, const Date& d) { out << d._year << "年" << d._month << "月" << d._day << "日" << endl; return out; } inline istream& operator>>(istream& in, Date& d) { in >> d._year >> d._month >> d._day; return in; }
四、兩個(gè)日期相減,返回天數(shù)
1.這個(gè)模塊的實(shí)現(xiàn)非常的有意思,利用了一個(gè)編程技巧假設(shè),我們不知道哪個(gè)對(duì)象的日期更大一些,那我們就先假設(shè)一下,如果判斷錯(cuò)誤,只要糾正一下即可。
然后定義一個(gè)計(jì)數(shù)器,讓較小日期自增,直到和較大日期相等為止,最后的計(jì)數(shù)器就是日期之間相差的天數(shù),這個(gè)天數(shù)既有可能是正,也有可能是負(fù),所以這里利用了flag標(biāo)志位,返回flag和cnt的乘積。
int Date::operator-(const Date& d)const { Date max = *this; Date min = d; int flag = 1; if (*this < d) { max = d; min = *this; flag = -1; } int cnt = 0; while (min != max) { ++min; ++cnt; } return cnt * flag; }
五、日期類(lèi)完整代碼
1.Date.h
#pragma once #include <iostream> using namespace std; class Date { public: friend ostream& operator<<(ostream& out, const Date& d); friend istream& operator>>(istream& in, Date& d); int GetMonthDay(int year, int month) { //靜態(tài)數(shù)組,每次調(diào)用不用頻繁在棧區(qū)創(chuàng)建數(shù)組 static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) { return 29; } else { return monthDayArray[month]; } } Date(int year = 1, int month = 1, int day = 1) { _year = year; _month = month; _day = day; // 檢查日期是否合法 if (!(year >= 1&& (month >= 1 && month <= 12)&& (day >= 1 && day <= GetMonthDay(year, month)))) { cout << "非法日期" << endl; } } //拷貝構(gòu)造、賦值重載、析構(gòu)函數(shù)都不用自己寫(xiě) void Print()const { cout << _year << "年" << _month << "月" << _day << "日" << endl; } 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; Date& operator+=(int day); Date operator+(int day); Date& operator-=(int day); Date operator-(int day); Date& operator++();//前置++ Date operator++(int);//后置++ Date& operator--();//前置-- Date operator--(int);//后置-- // d1 - d2; int operator-(const Date& d)const; private: int _year; int _month; int _day; }; inline ostream& operator<<(ostream& out, const Date& d) { out << d._year << "年" << d._month << "月" << d._day << "日" << endl; return out; } inline istream& operator>>(istream& in, Date& d) { in >> d._year >> d._month >> d._day; return in; }
2.Date.cpp
#include "Date.h" bool Date::operator==(const Date& d)const { return _year == d._year && _month == d._month && _day == d._day; } bool Date::operator>(const Date& d) const { if (_year > d._year) { return true; } else if (_year == d._year && _month >> d._month) { return true; } else if (_year == d._year && _month == d._month && _day > d._day) { return true; } return false; } bool Date::operator>=(const Date& d) const { return *this > d || *this == d; } bool Date::operator<=(const Date& d) const { return !(*this > d); } bool Date::operator<(const Date& d) const { return !(*this >= d); } bool Date::operator!=(const Date& d) const { return !(*this == d); } Date& Date::operator+=(int day) { if (day < 0) { return *this -= abs(day); } _day += day; while (_day > GetMonthDay(_year, _month)) { _day -= GetMonthDay(_year, _month); ++_month; if (_month == 13) { _month = 1; ++_year; } } return *this; } Date Date::operator+(int day) { Date ret(*this); ret += day; return ret; } Date& Date::operator-=(int day) { if (day < 0) { return *this += abs(day); } _day -= day; while (_day <= 0) { --_month; if (_month == 0) { _month = 12; --_year; } _day += GetMonthDay(_year, _month); } return *this; } Date Date::operator-(int day) { Date ret(*this); ret -= day; return ret; } Date& Date::operator++() { return *this += 1; } Date Date::operator++(int) { Date ret(*this); *this += 1; return ret; } Date& Date::operator--() { return *this -= 1; } Date Date::operator--(int) { Date ret(*this); *this -= 1; return ret; } int Date::operator-(const Date& d)const { Date max = *this; Date min = d; int flag = 1; if (*this < d) { max = d; min = *this; flag = -1; } int cnt = 0; while (min != max) { ++min; ++cnt; } return cnt * flag; }
3.Test.cpp
#include "Date.h" void TestDate1() { Date d1(2022, 10, 8); Date d3(d1); Date d4(d1); d1 -= 10000; d1.Print(); Date d2(d1); /*Date d3 = d2 - 10000; d3.Print();*/ (d2 - 10000).Print(); d2.Print(); d3 -= -10000; d3.Print(); d4 += -10000; d4.Print(); } void TestDate2() { Date d1(2022, 10, 8); Date d2(d1); Date d3(d1); Date d4(d1); (++d1).Print(); // d1.operator++() d1.Print(); (d2++).Print(); // d2.operator++(1) d2.Print(); (--d1).Print(); // d1.operator--() d1.Print(); (d2--).Print(); // d2.operator--(1) d2.Print(); } void TestDate3() { Date d1(2022, 10, 10); Date d2(2023, 7, 1); cout << d2 - d1 << endl; cout << d1 - d2 << endl; } void TestDate4() { Date d1, d2; cin >> d1 >> d2; cout << d1 << d2 << endl; // operator<<(cout, d1); cout << d1 - d2 << endl; } int main() { //TestDate1(); TestDate4(); return 0; }
以上就是C++實(shí)現(xiàn)日期類(lèi)的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于C++日期類(lèi)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python設(shè)計(jì)模式編程中的備忘錄模式與對(duì)象池模式示例
這篇文章主要介紹了Python設(shè)計(jì)模式編程中的備忘錄模式與對(duì)象池模式,文中分別舉了表單和線(xiàn)程的相關(guān)示例,需要的朋友可以參考下2016-02-02c#實(shí)現(xiàn)隱藏與顯示任務(wù)欄的方法詳解
本篇文章是對(duì)c#中任務(wù)欄隱藏與顯示的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06C#中后臺(tái)post請(qǐng)求常用的兩種方式總結(jié)
這篇文章主要介紹了C#中后臺(tái)post請(qǐng)求常用的兩種方式總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06c# SQLHelper(for winForm)實(shí)現(xiàn)代碼
數(shù)據(jù)連接池c# SQLHelper 實(shí)現(xiàn)代碼2009-02-02使用C#實(shí)現(xiàn)RTP數(shù)據(jù)包傳輸 參照RFC3550
本篇文章小編為大家介紹,使用C#實(shí)現(xiàn)RTP數(shù)據(jù)包傳輸 參照RFC3550,需要的朋友參考下2013-04-04