欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報邀請碼778899分享:開發(fā)語言 C++——日期類

柚子快報邀請碼778899分享:開發(fā)語言 C++——日期類

http://yzkb.51969.com/

前言:哈嘍小伙伴們,在上一篇文章中我們對C++類與對象的前半段知識進(jìn)行了簡單的分享,其中比較重要的莫過于C++類的六個默認(rèn)成員函數(shù)。

所以這篇文章,我們通過實現(xiàn)一個完整的日期的操作,來對這些成員函數(shù)有一個更加深入的理解。

目錄

一.基本框架

二.日期的比較

三.日期的加減運算

?1.得到月的天數(shù)

2.日期的加運算

3.日期的減運算

4.日期的++--運算

5.日期減日期

6.日期的輸入輸出

7.存在的問題

總結(jié)

一.基本框架

根據(jù)我們過去實現(xiàn)項目的方法,我們需要將聲明與定義分離,同時還要實現(xiàn)測試代碼與源代碼分離,所以我們需要三個文件:

隨后進(jìn)行類的創(chuàng)建,基本成員函數(shù)的實現(xiàn),以及測試代碼的創(chuàng)建等框架。?

隨后進(jìn)行框架的測試:

二.日期的比較

兩個日期之間的比較方式有很多種:>、<、<=、>=、==、!=

這些就需要我們的賦值運算符構(gòu)造函數(shù)出馬了。

上篇文章我們已經(jīng)知道的“>”的寫法:

bool operator>(const Date& d)

{

if (_year > d._year)

return true;

else if (_year == d._year)

{

if (_month > d._month)

return true;

else if (_month == d._month)

return _day > d._day;

else

return false;

}

else

return false;

}

但是就這一個的寫法,就已經(jīng)是很多,很麻煩的一段代碼了,難道像這樣的代碼我們一共要寫6個嗎???當(dāng)然不需要,我們要知道,這些符號之間都有兩兩互補(bǔ)的關(guān)系。

比如說,我們現(xiàn)在寫出了“>”,那么“<=”不就是“>”取反嗎:

bool Date::operator<=(const Date& d)

{

return !(*this > d);

}

?我們建議把“==”給寫出來,因為它比較容易寫:

bool Date::operator==(const Date& d)

{

return _year == d._year

&& _month == d._month

&& _day == d._day;

}

如此一來,“!=”的寫法就會是:

bool Date::operator!=(const Date& d)

{

return !(*this == d);

}

現(xiàn)在我們同時擁有了“>”和“==”,那么將兩者結(jié)合自然就得到了“>=”:

bool Date::operator>=(const Date& d)

{

return *this > d || *this == d;

}

這樣是不是非常的簡潔???其余符號的代碼就不一一列舉啦,詳情請看最后的完整代碼展示。

三.日期的加減運算

日期的加減是一個相對比較困難的運算,它不像數(shù)字的加減那樣簡單,因為不僅存在大小月的天數(shù)不一,而且每四年還會出現(xiàn)閏年的特殊情況,這樣就會導(dǎo)致進(jìn)位非常的麻煩。下面我們就來詳細(xì)分享一下,如此復(fù)雜的日期運算,到底該怎么實現(xiàn)。?

?1.得到月的天數(shù)

首先很重要的一點就是我們要能夠知道每個月都分別有多少天,同時還有2月這個特殊的月份,我們通過一個函數(shù)來實現(xiàn):

int GetMonthdays(int year, int month)

{

assert(month > 0 && month < 13);

int Monthdays[12] = { 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;

}

return Monthdays[month - 1];

}

首先要做的就是assert斷言,防止月份輸入錯誤,其次因為閏年是斯四年一次,所以我們默認(rèn)情況下都是平年,通過數(shù)組來記錄,能夠方便獲取。最后就是進(jìn)行閏年二月的判斷,如果2月,我們就去判斷一下是否是閏年。?

2.日期的加運算

我們之間搬出代碼來講:

Date& Date::operator+(int day)

{

_day += day;

while(_day > GetMonthdays(_year, _month))

{

_day -= GetMonthdays(_year, _month);

_month++;

if (_month == 13)

{

_year++;

_month = 1;

}

}

return *this;

}

依舊是使用賦值運算符構(gòu)造函數(shù),我們直接讓_day加上我們要加的天數(shù),隨后進(jìn)行判斷,如果相加之后的天數(shù)大于當(dāng)月的天數(shù),就讓_day減去該月的天數(shù),剩下的自然就是下個月的天數(shù),同時月份+1,如果月份+1后是13,那就需要向年進(jìn)一,同時月份回到1。

之所以使用循環(huán),是因為如果我要加100天,那向月的進(jìn)位就不止1了,所以要循環(huán)往復(fù)的判斷。

下面我們進(jìn)行測試:

#include"Date.h"

int main()

{

Date d1(2024, 2, 1);

Date d2 = d1 + 30;

d2.Print();

return 0;

}

結(jié)果如下:?

1+30 = 31,而2024年恰巧就是閏年,所以2月有29天,31 - 29 = 2,所以結(jié)果為2024/3/2。?

但是這樣的寫法看似完美,但實際上存在一個很大的錯誤,來看代碼:

#include"Date.h"

int main()

{

Date d1(2024, 2, 1);

Date d2 = d1 + 30;

d2.Print();

d1.Print();

return 0;

}

?我們是讓d2對象去接收d1對象的日期加上20天后的日期,但實際上:

d1對象的日期也發(fā)生了改變。

這個錯誤其實也是可以理解的,因為我們在函數(shù)中直接默認(rèn)進(jìn)行操作的就是d1的成員變量。而這樣的運算,實際上是“+=”運算。

所以想要保證d1的成員變量不變,就必須創(chuàng)建一個臨時變量來代替:

Date Date::operator+(int day)

{

Date tmp(*this);

tmp._day += day;

while (tmp._day > GetMonthdays(tmp._year, tmp._month))

{

tmp._day -= GetMonthdays(tmp._year, tmp._month);

tmp._month++;

if (tmp._month == 13)

{

tmp._year++;

tmp._month = 1;

}

}

return tmp;

}

?創(chuàng)建臨時變量,就用到了我們的拷貝構(gòu)造函數(shù),使用tmp臨時變量代替d1對象進(jìn)行操作。

值得注意的一點是,由于tmp是臨時的變量,當(dāng)這個函數(shù)結(jié)束時就不存在了,所以其作為返回值時,返回類型不能是引用。?

再進(jìn)行測試,結(jié)果如下:

?

3.日期的減運算

理解了加運算之后,減運算的寫法相信小伙伴們都能夠自己悟出來了。

唯一值得注意的是,日期沒有0天:

//日期減等運算

Date& Date::operator-=(int day)

{

_day -= day;

while (_day <= 0)

{

_month--;

if (_month == 0)

{

_year--;

_month = 12;

}

_day += GetMonthdays(_year, _month);

}

return *this;

}

這里我們先來實現(xiàn)一下“-=”運算,注意while循環(huán)的判斷條件,因為_day不可能等于0。

如果當(dāng)月剩余的天數(shù)不夠用,就需要去借用上個月的天數(shù)繼續(xù)減。結(jié)果如下:

那么問題來了,博主為什么要先實現(xiàn)“-=”呢????

下面我們就來看看“-”運算的實現(xiàn):

//日期減運算

Date Date::operator-(int day)

{

Date tmp(*this);

tmp -= day;

return tmp;

}

怎么樣,有沒有很震驚,為了不改變d1對象,我們確實創(chuàng)建了臨時變量tmp,但是我們大可不必去再寫像上邊那樣的一大長串代碼,因為我們已經(jīng)有“-=”運算了,所以我們直接讓tmp去進(jìn)行“-=”運算,就可以得到結(jié)果:?

而我們前邊實現(xiàn)過的加運算同樣可以借用“+=”運算來寫:

//日期加運算

Date Date::operator+(int day)

{

Date tmp(*this);

tmp += day;

return tmp;

}

4.日期的++--運算

我們知道,“++”和“--”運算都有前置和后置兩種方式,那么我們該怎么用構(gòu)造函數(shù)去分別實現(xiàn)呢?

不管是前置還是后置,它們都會有++,那么我們使用賦值運算符重載函數(shù),函數(shù)名該怎么寫?難道也是一前一后???

并不是,實際上是使用函數(shù)重載來區(qū)分它們:

//前置++運算

Date& operator++();

//后置++運算

Date operator++(int);

對于后置++,給它一個int參數(shù),但是該參數(shù)并不會使用,只是用作編譯器的區(qū)分。

那么兩個函數(shù)又該怎么實現(xiàn)呢????

要注意的是,前置++是先加1,再給值,而后置++是先給值,再++,所以后者就需要一個臨時變量,我們同樣借用一下“+=”函數(shù):

//前置++運算

Date& Date::operator++()

{

*this += 1;

return *this;

}

//后置++運算

Date Date::operator++(int)

{

Date tmp = *this;

*this += 1;

return tmp;

}

再來進(jìn)行測試:?

?

如此便可以實現(xiàn)“++”的運算符重載?!?-”與之類似,博主這里就不做展開講解。

5.日期減日期

上邊我們講的日期減運算,是用日期去減去明確的天數(shù)得到一個新的日期。

那么現(xiàn)在如果想用一個日期減去另一個日期,計算兩個日期之間有多少天,又該怎么搞呢???

這個事情看似復(fù)雜,實則代碼寫起來也挺簡單,現(xiàn)在給大家一個思想:

先去比較兩個日期誰大,然后我讓小的一直去++,并計數(shù),直到跟大的相等,計數(shù)的結(jié)果不就是兩者的相差天數(shù)嗎???

//日期-日期

int Date::operator-(const Date& d)

{

Date max = *this;

Date min = d;

int flag = 1;

if (*this < d)

{

flag = -1;

max = d;

min = *this;

}

int n = 0;

while (min < max)

{

min++;

n++;

}

return n * flag;

}

先默認(rèn)前一個值為較大值,后一個為較小值,然后去比較,如果前一個實際上是較小值,則進(jìn)行互換,同時創(chuàng)建一個flag,如果是大-小,結(jié)果即為整數(shù),反之則賦值為-1,結(jié)果為負(fù)數(shù),測試如下:

?

6.日期的輸入輸出

我們前邊講述的日期,都是我們在創(chuàng)建對象時就給定的數(shù)據(jù),輸出時也是用的Print函數(shù)。而且我們知道,cin和cout是無法直接輸入輸出自定義類型的數(shù)據(jù)的。

那現(xiàn)在我們就想先創(chuàng)建一個對象,然后通過cin和cout來輸入輸出數(shù)據(jù),該如何實現(xiàn)呢???

首先我們要知道,cin是istream類型的對象,而cout是ostream類型的對象,那么我們就可以通過賦值運算符重載函數(shù)來重載“>>”和“<<”兩個符號來實現(xiàn):

//日期輸出

void Date::operator<<(ostream& out)

{

out << _year << "年" << _month << "月" << _day << "日" << endl;

}

但是這樣的寫法存在問題:

賦值運算符重載函數(shù)定義在類中作為成員函數(shù)時,其第一個參數(shù)就會是默認(rèn)的隱藏的this參數(shù),也就是d1,而cout則是第二個參數(shù),這就導(dǎo)致我們調(diào)用函數(shù)時兩個實參的順序存在問題,如果將其改為d1<

但是這顯然不符合我們C++的使用規(guī)范,所以想要恢復(fù)順序,就需要將此函數(shù)定義在類外,交換兩個形參的位置:

但是這個時候又出現(xiàn)了問題,因為該函數(shù)在類外,而類的成員變量是私有的,我們不能使用:

?

又該如何解決這個問題呢?

這就需要用到關(guān)鍵字:friend,通過friend,將類外函數(shù)在類內(nèi)進(jìn)行友元聲明,就可以啦:

?

但是此時還有一個問題,在C++中cout是支持同時輸出多個變量的,但是我們定義的函數(shù)卻不行:

?

這是因為按照從左到右的順序,執(zhí)行完cout<

//日期輸出

ostream& operator<<(ostream& out, const Date& d)

{

out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

return out;

}

?測試如下:

那么知道輸出之后,輸入的寫法就與之類似了:

//日期輸入

istream& operator>>(istream& in, Date& d)

{

in >> d._year >> d._month >> d._day;

return in;

}

首先就是返回值類型和參數(shù)類型為istream&,其次要注意參數(shù)d不能用const修飾,因為就是要給它輸入值。

測試如下:

7.存在的問題

?到這里呢,日期類的所有基本功能已經(jīng)全部實現(xiàn)了,但是任然存在一個問題:

我們不小心將2月的天數(shù)傳了個40,這怎么能允許呢,2月最多也就29天,40天怎么可能呢?但是發(fā)現(xiàn)d2還是按部就班的進(jìn)行了“+”運算,這就會出現(xiàn)很大的問題。所以我們需要進(jìn)行傳入檢查。

因為在構(gòu)造函數(shù)和輸入函數(shù)中都需要進(jìn)行檢查,所以我們需要一個創(chuàng)建一個函數(shù):

//檢查日期合法性

bool Date::CheckInvalid()

{

if (_year <= 0 || _month < 1 || _month > 12

|| _day < 1 || _day > GetMonthdays(_year, _month))

return false;

else

return true;

}

?分別判斷年,月,日是否都合法。

//初始化

Date::Date(int year, int month, int day)

{

_year = year;

_month = month;

_day = day;

if (!CheckInvalid())

{

cout << *this << "該日期非法" << endl;

exit(-1);

}

}

構(gòu)造函數(shù)中使用,若非法直接結(jié)束程序:

//日期輸入

istream& operator>>(istream& in, Date& d)

{

while(1)

{

in >> d._year >> d._month >> d._day;

if (!d.CheckInvalid())

cout << "輸入的日期非法,請重新輸入:" << endl;

else

break;

}

return in;

}

輸入函數(shù)中使用,若非法則重新輸入:?

?

總結(jié)

日期類的實現(xiàn)到這里就分享完啦,希望能夠幫助小伙伴們更加深入的理解類的內(nèi)部結(jié)構(gòu)及其成員函數(shù)的操作實現(xiàn)。

喜歡博主文章的小伙伴記得一鍵三連哦,我們下期再見!

柚子快報邀請碼778899分享:開發(fā)語言 C++——日期類

http://yzkb.51969.com/

參考閱讀

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/18960607.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄