詳解如何用C++寫一個日期計算器
前言
寫一個日期計算器對學(xué)習(xí)的意義也很大。初學(xué)C++,接觸了類和對象的概念,又認(rèn)識了默認(rèn)成員函數(shù),然后又學(xué)習(xí)了運(yùn)算符的重載。而日期計算器就很好的涵蓋了這些知識。能很好的幫助我們復(fù)習(xí)學(xué)過的知識。
代碼的布局
建兩個 .cpp文件:Date.cpp Test.cpp
建一個 .h文件 :Date.h
作用:Date.h聲明一個類 , Date.cpp類的方法的具體實現(xiàn), Test.cpp測試方法的邏輯
設(shè)計數(shù)據(jù)
年:_year 月:_month 日:_day
變量名前面加“ _ ”符號,是為了和普通的數(shù)據(jù)或一些參數(shù)做區(qū)分。增加代碼可讀性。
方法聲明
// 獲取某年某月的天數(shù) int GetMonthDay(int year, int month); // 全缺省的構(gòu)造函數(shù) Date(int year = 2024, int month = 4, int day = 18); // 拷貝構(gòu)造函數(shù) Date(const Date& d); // 賦值運(yùn)算符重載 Date& operator=(const Date& d); // 析構(gòu)函數(shù) ~Date(); // 日期+=天數(shù) Date& operator+=(int day); //其結(jié)果為日期 // 日期+天數(shù) Date operator+(int day); // 日期-天數(shù) Date operator-(int day); // 日期-=天數(shù) Date& operator-=(int day); // 前置++ Date& operator++(); //天數(shù)加1 // 后置++ Date operator++(int); // 后置-- Date operator--(int); //天數(shù)減1 // 前置-- Date& operator--(); // >運(yùn)算符重載 bool operator>(const Date& d); //比較日期大小 // ==運(yùn)算符重載 bool operator==(const Date& d); // >=運(yùn)算符重載 bool operator >= (const Date& d); // <運(yùn)算符重載 bool operator < (const Date& d); // <=運(yùn)算符重載 bool operator <= (const Date& d); // !=運(yùn)算符重載 bool operator != (const Date& d); // 日期-日期 返回天數(shù) int operator-(const Date& d);
聲明的方法要有其意義,比如日期和天數(shù)相乘就沒有意義,也沒必要聲明。
方法的實現(xiàn)
獲取某年某月的天數(shù)
int GetMonthDay(int year, int month);
閏年
一年有365天,但地球公轉(zhuǎn)的周期比一年多了大約5.82個小時。所以每過4年,二月的28天就要變成29天,即4年一潤。但每四年都要潤一次的話,每過100年,我們計算的天數(shù)要比地球公轉(zhuǎn)的天數(shù)多了大概0.75天,所以二月的28天保持不變,即百年不潤。100年不潤是為了補(bǔ)足4年一潤的精度,而400一潤是為了補(bǔ)足100年不潤的精度。只有這樣,日期才不會與四季脫離。
總結(jié)就是:四年一潤,百年不潤,四百年又一潤。
翻譯成計算機(jī)語言就是
year % 4 == 0 && year % 100 != 0 || year % 400 == 0
有了閏年的概念,那么獲取某年某月的天數(shù)的代碼就可以實現(xiàn)了
// 獲取某年某月的天數(shù) int Date::GetMonthDay(int year, int month) { assert(month > 0 && month < 13); static int a[13] = { -1,31, 28, 31, 30, 31, 30, 31, 31, 30, 31,30,31 }; if (2 == month && year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { return a[month] + 1; } else { return a[month]; } }
下圖是代碼控制的細(xì)節(jié)
下面加*的函數(shù)不做重點(diǎn)
*全缺省的構(gòu)造函數(shù)
Date(int year = 2024, int month = 4, int day = 18);
Date::Date(int year, int month, int day) { _year = year; _month = month; _day = day; }
注意:全缺省構(gòu)造函數(shù)在定義的時候不需要給缺省值。
拷貝構(gòu)造函數(shù)
Date(const Date& d);
Date::Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; }
賦值運(yùn)算符重載
Date& operator=(const Date& d);
Date& Date::operator=(const Date& d) { if (this != &d) { _year = d._year; _month = d._month; _day = d._day; return *this; } return *this; }
析構(gòu)函數(shù)
因為沒有涉及到資源管理可以不寫,編譯器會自動生成默認(rèn)的析構(gòu)函數(shù)。
日期+=天數(shù)
Date& operator+=(int day);
思路:可以把要加的天數(shù)直接加到日期的天數(shù)上,如果日期的天數(shù)沒有超過該月的最大天數(shù),直接返回日期。如果超過了,就寫個循環(huán)往前進(jìn)位,直到日期的天數(shù)小于該月的最大天數(shù),然后再返回日期。
邏輯示意圖
代碼
Date& Date::operator+=(int day) { _day += day; //把天數(shù)加到日期的天數(shù)上 while (_day > GetMonthDay(_year, _month)) //如果日期的天數(shù)大于該月最大天數(shù)就進(jìn)位 { _day -= GetMonthDay(_year, _month); //要想進(jìn)位,得把該月的最大天數(shù)減掉 ++_month; //進(jìn)位 if (_month > 12) //如果月不合法就調(diào)整月 { ++_year; _month = 1; } } return *this; //返回日期,因為出了作用域不會銷毀,可以引用返回 }
*this是返回聲明在頭文件中的日期類,該類出了該函數(shù)的作用域不會銷毀,所以傳引用返回,提高效率。
日期+天數(shù)
Date operator+(int day);
實現(xiàn)日期+天數(shù)的時候不用把類似于日期+=天數(shù)的邏輯再寫一遍,可以直接復(fù)用。
Date Date::operator+(int day) { Date tmp = *this; //在實例化對象的時候,調(diào)用拷貝構(gòu)造函數(shù),將日期類的數(shù)據(jù)拷貝給臨時對象 tmp += day; //直接復(fù)用+=的邏輯 return tmp; }
日期加天數(shù)不能改變?nèi)掌诘闹?,所以要?chuàng)建臨時對象。臨時對象出了作用域就銷毀了,所以不能傳引用返回。
日期-天數(shù)
Date operator-(int day);
在實現(xiàn)日期+=天數(shù)和日期+天數(shù)的時候,先實現(xiàn)了+=的邏輯,在實現(xiàn)+的邏輯的時候復(fù)用+=的邏輯。現(xiàn)在反過來,先實現(xiàn)-的邏輯,在實現(xiàn)-=的邏輯的時候復(fù)用-的邏輯。
思路:把天數(shù)直接和日期中的天數(shù)相減。若不為負(fù)數(shù),直接返回。若為負(fù)數(shù),則需要寫個循環(huán)不斷向前借位,如果把月借成負(fù)數(shù)就向年借,然后調(diào)整月,再調(diào)整日,直到日大于零為止。因為日期-天數(shù)不改變?nèi)掌?,所以要?chuàng)建臨時的對象。
代碼
Date Date::operator-(int day) { Date d = (*this); //創(chuàng)建臨時對象,把日期類的數(shù)據(jù)拷貝給臨時對象 d._day -= day; //讓日期的天數(shù)直接和天數(shù)相減 while (d._day <= 0) //日期的天數(shù)小于零就調(diào)整 { --d._month; //該月已經(jīng)是負(fù)的,應(yīng)該往下個月借天數(shù) if (d._month <= 0) //月不合法就調(diào)整月 { --d._year; d._month = 12; } d._day += GetMonthDay(d._year, d._month); //把該月的所有天數(shù)都借給日期的天數(shù) } return d; }
邏輯示意圖
因為臨時對象出了作用域要銷毀,所以不能傳引用返回。
日期-=天數(shù)
Date& operator-=(int day);
直接復(fù)用-的邏輯,代碼如下
Date& Date::operator-=(int day) { return *this = *this - day; }
前置++
Date& Date::operator++()
實現(xiàn)前置++就不需要復(fù)雜的邏輯了,只需要控制年月日的進(jìn)位即可。代碼如下
Date& Date::operator++() //前置++需要先++在使用,所以不需要創(chuàng)建臨時對象,返回值可以是引用 { ++_day; //天數(shù)加一 if (_day > GetMonthDay(_year, _month)) //如果天數(shù)不符合該月最大天數(shù),則需要調(diào)整 { ++_month; //讓月加一 if (_month > 12) //月不合法就調(diào)整月 { ++_year; _month = 1; } _day = 1; 讓天數(shù)置一 } return *this; //返回該類 }
后置++
Date Date::operator++(int)
可直接復(fù)用前置++,后置++需要先使用再++,所以需要創(chuàng)建臨時對象,代碼如下
Date Date::operator++(int) { Date d = *this; ++(*this); return d; }
后置--
Date Date::operator--(int)
與++的實現(xiàn)不同,--的話先實現(xiàn)后置再實現(xiàn)前置。代碼如下
Date Date::operator--(int) { Date d = *this; // 創(chuàng)建臨時對象,保存日期類中的值 --_day; //日期類中的天數(shù)減一 if (_day <= 0) //這里可以不用寫小于,因為一天一天的減是不可能跨過零來到負(fù)數(shù)的 { --_month; //如果天數(shù)等于零了,就需要借上個月的天數(shù),月要減一 if (_month <= 0) //月不合法就調(diào)整月 { --_year; _month = 12; } _day = GetMonthDay(_year, _month); //把天數(shù)置成該月最大天數(shù) } return d; //返回保存好的數(shù)據(jù),這樣就實現(xiàn)了后置--的效果 }
前置--
Date& Date::operator--()
直接復(fù)用后置--,代碼如下
Date& Date::operator--() { (*this)--; return *this; }
實現(xiàn)比較大小運(yùn)算符重載思路
小編先理一下思路,方便大家理解。
要實現(xiàn)比較大小的運(yùn)算符有 >, ==, >=, < , <= , !=。只需要實現(xiàn)> 和 ==就可以復(fù)用并實現(xiàn)后四個運(yùn)算符。如下圖
>運(yùn)算符重載
bool Date::operator>(const Date& d)
代碼如下
bool Date::operator>(const Date& d) { if (_year > d._year) //年大就大 { return true; } if (_year == d._year)//年相等比月 { if (_month > d._month) //月大就大 { return true; } if (_month == d._month) //月相等比天 { if (_day > d._day) //天大就大 { return true; } } } return false; //不然就是小的 }
==運(yùn)算符重載
bool Date::operator==(const Date& d)
年月日都相等才相等,代碼如下
bool Date::operator==(const Date& d) { return _year == d._year && _month == d._month && _day == d._day; }
*> = 運(yùn)算符復(fù)用實現(xiàn)其他比較運(yùn)算符重載
這里不做重點(diǎn),大家可以點(diǎn)擊“目錄”,再點(diǎn)擊”日期-日期“即可跳過
>=運(yùn)算符重載
bool Date::operator >= (const Date& d) { return (*this) > d || (*this) == d; }
<運(yùn)算符重載
bool Date::operator < (const Date & d) { return !((*this) >= d); }
<=運(yùn)算符重載
bool Date::operator <= (const Date& d) { return !((*this) > d); }
!=運(yùn)算符重載
bool Date::operator != (const Date& d) { return !((*this) == d); }
日期-日期
int Date::operator-(const Date& d)
參數(shù):第一個參數(shù)為隱含的this指針,第二個參數(shù)為 const Date&,傳引用是為了提高傳值效率。
返回值:日期-日期代表的是兩個日期之間相差的天數(shù),返回值類型為 int。
思路1:可以先算出兩個日期相差多少年,把每一年的總天數(shù)加在一起,但要判斷該年是否為閏年。
思路2:直接復(fù)用++運(yùn)算符,在設(shè)一個變量,每加一天,變量就加一。
下面用思路2實現(xiàn),代碼如下
int Date::operator-(const Date& d) { int counst = 0; //定義一個變量,保存天數(shù) if ((*this) == d) //如果兩個日期相等,直接返回零 { return 0; } else if ((*this) > d) { Date tmp = d; //如果this的的日期大,就給d創(chuàng)建臨時變量tmp,然tmp小日期去追this大日期 while ((*this) != tmp) { ++tmp; counst++; } return counst; } else { Date tmp = (*this); //同上 while (tmp != d) { ++tmp; counst++; } return counst; } }
代碼錯誤和bug分享
小編在實現(xiàn)方法的時候把域作用限定符寫在了返回值的前面,如下
大家不要這樣寫呀。
在寫前置++的時候?qū)懥艘粋€不易察覺的bug,寫完測了幾組數(shù)據(jù)沒問題,但其他方法調(diào)用的時候卻出問題了,調(diào)了好久才發(fā)現(xiàn),如下代碼,大家能看出來哪里出錯了嗎
// 前置++ Date& Date::operator++() // bug分享 { ++_day; if (_day > GetMonthDay(_year, _month)) { ++_month; if (_month > 12) { ++_year; _month = 1; _day = 1; } } return *this; }
哈哈,其實正是因為邏輯太順了,忽略了一些情況如下圖
大家在測方法的時候盡量要跨過幾個平年和閏年,這樣方法才有可信度。
以上就是詳解如何用C++寫一個日期計算器的詳細(xì)內(nèi)容,更多關(guān)于C++日期計算器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于matlab實現(xiàn)DCT數(shù)字水印嵌入與提取
數(shù)字水印技術(shù)是將一些標(biāo)識信息直接嵌入數(shù)字載體當(dāng)中,?或間接表示在信號載體中,?且不影響原載體的使用價值。本文主要為大家介紹了基于matlab如何實現(xiàn)數(shù)字水印的嵌入與提取,感興趣的可以學(xué)習(xí)一下2022-01-01c++中為什么可以通過指針或引用實現(xiàn)多態(tài)詳解
這篇文章主要給大家介紹了關(guān)于c++中為何可以通過指針或引用實現(xiàn)多態(tài),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04C++實現(xiàn)LeetCode(105.由先序和中序遍歷建立二叉樹)
這篇文章主要介紹了C++實現(xiàn)LeetCode(105.由先序和中序遍歷建立二叉樹),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07