模擬實現Date類
阿新 • • 發佈:2019-02-18
日期類是很常用的一個類,我們要模仿實現的就是日常生活中會用到的一些功能。
首先給出Date類的標頭檔案:
class Date { friend std::ostream& operator<<(std::ostream& _cout, const Date& d); friend std::istream& operator>>(std::istream& _cin, Date& d); public: Date(int year = 1970, int month = 1, int day = 1); ~Date(); Date(const Date& d); int getYear() const; int getMonth() const; int getDay() const; Date& operator=(const Date& d); Date operator+(int days) const; Date& operator+=(int days); Date operator-(int days) const; Date& operator-=(int days); int operator-(const Date& d) const; Date& operator++(); Date operator++(int); Date& operator--(); Date operator--(int); 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; private: bool isLeapYear() const; int getDayInMonth() const; int _year; int _month; int _day; };
下面我們來一一實現它們:
//建構函式 //使用初始化引數列表,為成員變數一一賦值即可。 //當初始化完成後,用assert語句判斷成員變數的合法性。 //如果不合法,返回異常。 Date::Date(int year, int month, int day) :_year(year) ,_month(month) ,_day(day) { assert(this->_month < 13 && this->_month > 0 && this->_day > 0 && this->_day < getDayInMonth()); } //解構函式 //將成員變數賦值為0 Date::~Date() { _year = 0; _month = 0; _day = 0; } //拷貝建構函式 //這裡的形參只能用引用型別。 //如果直接用的是物件型別,那麼就會在傳參的時候建立一個形參d, //而d是用實參拷貝構造的,這樣就會一直迴圈下去。 Date::Date(const Date& d) :_year(d._year) ,_month(d._month) ,_day(d._day) {} //返回年份 int Date::getYear() const { return this->_year; } //返回月份 int Date::getMonth() const { return this->_month; } //返回日期 int Date::getDay() const { return this->_day; } //賦值運算子過載 //當 d 不是當前物件時,將d的成員變數的值,依次賦給當前物件的成員變數。 //並且返回當前物件的引用。 //由於這裡當前物件的生命週期比函式長,因此可以直接返回當前物件的引用。 //省去了建立臨時變數返回的步驟,提高了效率。 Date& Date::operator=(const Date& d) { if (this != &d) { this->_year = d._year; this->_month = d._month; this->_day = d._day; } return *this; } //判斷年份是否是閏年 //在Date類外,判斷是否是閏年,可以由使用者自行判斷。 //這裡的作用是為了輔助實現其他功能,因此直接定義為私有,對外不可見。 bool Date::isLeapYear() const { return (this->_year % 400 == 0) || ((this->_year % 4 == 0) && (this->_year % 100 != 0)); } //判斷日期的合法性 //用來檢測日期的合法性,確保日期是正確的。 //需要注意的就只有,當是閏年時,二月日期為29天。否則,為28天。 int Date::getDayInMonth() const { int daynumber[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (this->isLeapYear()) { daynumber[1] = 29; } return daynumber[this->_month - 1]; } //+運算子過載 //實現的原理為: //先將days全部加在成員變數_day上面, //用.getDayInMonth()函式判斷日期的合法性, //當日期不正確時,從_day中減去本月的天數,將月份增加一月, //一直迴圈,直到日期合法時,跳出迴圈,並且將計算完的物件返回。 //可以理解為:傳進來一個總天數days,從當前日期往前走,每走一個月,那麼從總日期中減去這個月的天數。 //然後所處的月份加一,然後從新的一月的第一天開始走。如果走完了一年,那麼月份變為一月,年份加一。 //因為 + 運算子並不會 影響當前物件本身,所以因該將結果儲存在臨時物件中, //又因為臨時物件是建立在棧上的,所以函式執行完之後會銷燬, //因此不能返回引用,所以返回的是建立的臨時物件的值。 Date Date::operator+(int days) const { Date temp(*this); if (days < 0) { return temp - (-days); } temp._day += days; while(temp._day > temp.getDayInMonth()) { //日期不合法 temp._day -= temp.getDayInMonth(); temp._month++; if (temp._month > 12) { temp._year++; temp._month = 1; } } return temp; } //+=運算子過載 //+=運算子會影響當前物件,所以直接在函式中,將 + 運算子計算的結果賦值給當前物件 //然後返回引用即可 Date& Date::operator+=(int days) { (*this) = (*this) + days; return *this; } //-運算子過載 //原理同上面+運算子,只是日期是倒著走 //實現的原理為: //先用成員變數_day減去days //當_day < 1 時,說明日期不合法。 //當日期不合法時,將月份減少一月,給_day加上上月的天數,說明往前退了一個月。 //一直迴圈,直到日期合法時,跳出迴圈,並且將計算完的物件返回。 //需要注意的是,在計算的時候,由於是往前退一個月,所以應該是先減去月份,再加上月份對應的日期, //或者是先加上上月的日期,然後再減去月份。 Date Date::operator-(int days) const { Date temp(*this); if (days < 0) { return temp + (-days); } temp._day -= days; while(temp._day < 1) { temp._month--; if (temp._month < 1) { temp._year--; temp._month = 12; } temp._day += temp.getDayInMonth(); } return temp; } //-=運算子過載 //原來相同,不做過多解釋 Date& Date::operator-=(int days) { (*this) = (*this) - days; return *this; } //<<運算子過載 //我們都知道,類的成員函式第一個引數為隱含的 this 指標。 //那麼對於 << 運算子如果直接過載,過載後,cout輸出流就變為了第二個引數, //而預設的 << 中,cout輸出流應該為第一個引數, //如果使用 cout << a 的形式呼叫,結果肯定是不對的。 //所以我們在類外進行操作符過載,然後定義為類的友元函式即可 std::ostream& operator<<(std::ostream& _cout, const Date& d) { _cout<< d._year<< "-"<< d._month<< "-"<< d._day; return _cout; } //>>運算子過載 std::istream& operator>>(std::istream& _cin, Date& d) { _cin>> d._year>> d._month>> d._day; return _cin; } //前置++運算子過載 //只需要對當前物件 + 1 然後返回當前物件即可 Date& Date::operator++() { (*this) += 1; return (*this); } //後置++運算子過載 //函式中形參僅僅是用於與前置++構成過載 //後置++ 是 執行完當前語句後才進行++操作, //所以我們應該先將當前物件儲存起來,等當前物件++完成之後, //再返回之前儲存的值,返回值不返回引用的原因為: //臨時變數為棧上元素,函式結束後,會銷燬掉 Date Date::operator++(int) { Date temp(*this); (*this) += 1; return temp; } //前置--運算子過載 Date& Date::operator--() { (*this) -= 1; return (*this); } //後置++運算子過載 Date Date::operator--(int) { Date temp(*this); (*this) -= 1; return temp; } //-運算子過載 //用兩個臨時物件maxxdate 和 mindate 分別儲存 d 和 當前物件中的 大日期 和 小日期 //寫一個迴圈,讓小日期加一個天數 當兩個日期相等時,返回加的日期即可。 int Date::operator-(const Date& d) const { int ret = 0; Date mindate; Date maxdate; if ((*this) == d) { return 0; } mindate = (*this) < d ? (*this) : d; maxdate = (*this) > d ? (*this) : d; while(1) { if (mindate + ret == maxdate) { break; } ++ret; } return ret; } //>運算子過載 //只需要判斷對應成員變數的大小即可 bool Date::operator>(const Date& d) const { return (this->_year > d._year) || (this->_year == d._year && this->_month > d._month) || (this->_year == d._year && this->_month == d._month && this->_day > d._day); } //>=運算子過載 bool Date::operator>=(const Date& d) const { return (*this) > d || (*this) == d; } //>運算子過載 bool Date::operator<(const Date& d) const { return (this->_year < d._year) || (this->_year == d._year && this->_month < d._month) || (this->_year == d._year && this->_month == d._month && this->_day < d._day); } //>=運算子過載 bool Date::operator<=(const Date& d) const { return (*this) < d || (*this) == d; } //==運算子過載 bool Date::operator==(const Date& d) const { return this->_year == d._year && this->_month == d._month && this->_day == d._day; } //!=運算子過載 bool Date::operator!=(const Date& d) const { return this->_year != d._year || this->_month != d._month || this->_day != d._day; }