文章目錄
- 一.四大預設成員函數
- 二.擷取某年某月的天數
- 三.日期+=天數和日期+天數
- 四.日期-=天數和日期-天數
- 五.日期比較
- 六.日期++和++日期
- 七.日期-日期
類和對象下呐主要是給大家講一下日期類的實作,至于為什麼不實作一個棧呐,那是因為目前學到的拷貝構造和指派重載都是屬于一種淺拷貝,而對于棧類我們需要使用深拷貝.
一.四大預設成員函數
這裡就不過多贅述了
class Date
{
public:
//全預設的構造函數
Date(int year = 2022, int month = 10, int day = 13)
{
_year = year;
_month = month;
_day = day;
if (!(_year > 0
&& _month >= 1 && _month <= 12
&& _day >= 1 && _day <= GetMonthDay(_year, _month)))
{
cout << "輸入的日期不合法" << endl;
Print();
}
}
//拷貝構造(其實對于日期類可以不用寫拷貝構造)
Date(Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
//指派重載(其實對于日期類可以不用寫拷貝構造)
Date& operator=(const Date& d2)
{
_year = d2._year;
_month = d2._month;
_day = d2._day;
return *this;
}
//析構函數:(其實對于日期類可以不用寫析構函數)
~Date()
{
_year = _month = _day = 0;
}
//列印日期
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
// 内置類型
int _year;
int _month;
int _day;
};
注意:下面所寫的函數都是日期類中的成員函數,這就意味着第一個參數都是隐含的this指針.
二.擷取某年某月的天數
年分為閏年和平年,月也分為1-12月,是以對于任意一年的12個月中每一個月的天數都是基本一樣的,次元在2月因為平年還是閏年相差一天.是以如果你要擷取某年某月的天數,就隻需對于在2月,且是閏年特殊+1天就可以.
//擷取某年某月的天數
int GetMonthDay(int year, int month)
{
int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = monthDay[month];
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0 && month == 2)
{
++day;
}
return day;
}
這裡值得一提的是,這裡有兩個可以優化的地方:
- 這裡的GetMonthDay()函數會被反複調用,且monthDay數組始終不變,是以建議定義成static靜态的
- 這裡的if判斷條件中,除法和取餘的運算符效率低,是以建議把month==2的條件寫在最前面
也就是這樣:
//擷取某年某月的天數
int GetMonthDay(int year, int month)
{
int _month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int _day = _month[month];
if (month == 2 && year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
{
++_day;
}
return _day;
}
三.日期+=天數和日期+天數
這裡可以通過舉例内置類型中+=和+運算符的使用特點
比如: c=a+=b和c=a+b這個例子
+=和+有一定的相似點:
傳回值和參數在類型和個數上都是一樣的
傳回值:Date&
參數1:隐含的this指針
參數2:要+的天數
但是,+=和+也有不同點:
c=a+=b這裡a的值在運算前後發生改變,
c=a+b這裡a的值在運算前後沒有改變.
這裡日期1+=天數和日期1+天數兩個函數的差別在于:
- 日期1+=天數中,日期1在運算前後發生改變,
- 日期1+天數中,日期1在運算前後沒有改變.
這裡先給大家實作operator+=(int day)函數:

ps:值得注意的是12到1月的轉變的時候,年份也要變
Date& operator+=(int day)
{
if (day < 0)
{
return *this -= -day;
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
_month = 1;
++_year;
}
}
return *this;
}
然後我們來實作一下,operator+(int day)函數:
這裡我們可以調用拷貝構造一個替身,讓替身的this發生改變,然後傳回替身,那麼就可以得到傳回值的同時,本體的this卻沒有發生改變.
//日期+天數
Date operator+(int day)
{
Date ret(*this);
if (day < 0)
{
ret -= -day;
return ret;
}
ret += day;
return ret;
}
四.日期-=天數和日期-天數
這裡和三的差別和相同點一樣,這裡不過多贅述.
這裡是日期-天數,那麼同樣的先全部減在天數上,然後借位,值得注意的是12到1月的轉變的時候,年份也要變
日期-=天數:
//日期-=天數
Date& operator-=(int day)
{
if (day < 0)
{
*this += -day;
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
_month = 12;
--_year;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
日期-天數:
//日期-天數
Date operator-(int day)
{
Date ret(*this);
if (day < 0)
{
ret += -day;
return ret;
}
ret -= day;
return ret;
}
ps:這裡傳入的天數一般都是正數,如果天數是負數的話,日原來的日期-天數就想當與日期+(-天數),同樣可以代碼複用.
五.日期比較
這裡代碼書寫起來比較簡單,這裡隻想給大家講一下複用的問題:寫了>和==其他日期比較,比如>=或者<或者!=都可以通過函數複用實作.
//==運算符
bool operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
//<運算符重載
bool operator<(const Date& d)
{
return !(*this > d || *this == d);
}
複用>和==的代碼,可以完成:
//>=運算符
bool operator>=(const Date& d)
{
return *this > d || *this == d;
}
//<=運算符
bool operator<=(const Date& d)
{
return !(*this > d);
}
//!=運算符
bool operator!=(const Date& d)
{
return !(*this == d);
}
六.日期++和++日期
首先,日期++和++日期也就是我們常說的b=a++和b=++a的差別:
但是這裡會出現一個比較尴尬的問題:
這裡的要寫的兩個運算符重載函數都使用的是一個運算符++,是以在書寫成員函數的時候函數名肯定都是
operator++,那麼當我們寫同時使用了d2=d1++和d2=++d1的時候,我們就寫一個函數肯定不行,是以C++文法就規定:
前置++和後置++的運算符重載函數使用operator++作為函數名,但是前置++的運算符重載函數不帶參數,後置++的運算符重載函數帶一個int類型作以區分.
//前置++: 比如y=++x;
Date& operator++()
{
*this += 1;
return *this;
}
//後置++: 比如y=x++;
Date operator++(int)
{
//記錄最初值
Date ret(*this);
*this += 1;
//傳回最初值
return ret;
}
值得注意的是,後置++中隻能傳值傳回,因為出了作用域ret就不存在了,不能傳引用傳回.
是以後置++這裡要調用兩次拷貝構造,一般推薦使用前置++
七.日期-日期
日期+日期就和指針+指針一樣,沒有任何意義,是以這裡不讨論日期+日期
另外運算的結果是兩個日期相差的天數,是以沒法日期-=日期
是以我們隻讨論日期-日期:
方法1:從日期1周遊到日期2計數,直至相等,推薦
//日期-日期:
int operator-(const Date& d)
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int count = 0;
while (min != max)
{
++min;
++count;
}
return flag * count;
}
方法2:標明一個起始位置0-1-1,分别計算日期1和日期2到起始位置的天數,然後兩個天數相減
注意:這裡要先求從0到_year-1這幾年的整年天數,再算目前年從1- _month-1這幾月的天數,最後再加上 _day
//日期-日期:
int GetDay(const Date& d)
{
int day = 0;
for (int i = 0; i < d._year; i++)
{
day += 365;
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)
{
++day;
}
}
for (int i = 1; i < d._month; i++)
{
day += GetMonthDay(d._year, i);
}
day += d._year;
return day;
}
int operator-(const Date& d)
{
int day1 = GetDay(*this);
int day2 = GetDay(d);
return day1 - day2;
}