1. 程式人生 > >模擬實現Date類

模擬實現Date類

日期類是很常用的一個類,我們要模仿實現的就是日常生活中會用到的一些功能。
首先給出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;
}

以上即為本篇全部內容,不足之處還望指正。