c++日期類(Date類)
1.Date中的建構函式
建構函式的作用可以說是對類變數的初始化(Init)如果我們不寫建構函式,系統會生成預設的建構函式,但是對於date類來說,這裡的預設建構函式什麼都不做,如果你建立了一個 Date d1,系統呼叫了預設建構函式,你會發現這裡的年月日都是隨機值,我們為了讓d1在初始化的時候就有一個確認的日期,所以得自己動手寫一個全預設的建構函式
我們在函式宣告中給一個確定的值,讓每個創建出來的日期類變數都有一個預設的初始值 1900,1,1
2.Date中的解構函式
解構函式的作用同構造函式是對應的,這裡是銷燬某些特定的成員變數,如我們用malloc申請出來的記憶體,如果不在解構函式中做特定的操作,就很可能導致記憶體洩漏,不過在Date中的成員並不需要特殊的去釋放他,他們生長在棧上,會隨函式棧楨的結束自動釋放掉,所以這裡就可以使用預設的解構函式,我們可以不用書寫
3.Date中的拷貝建構函式
建立物件的時候使用同類物件初始化,拷貝建構函式其實是一個建構函式的過載,如果我們沒有實現拷貝建構函式,系統也會自動生成拷貝建構函式,來依次拷貝類成員進行初始化
需要注意:拷貝建構函式必須使用傳引用的方式返回,否則會造成無窮遞迴
4.Date中的運算子過載
這裡我實現瞭如下幾個運算子的過載
需要注意的是
1.當返回一個Date類的變數時,我們使用傳值返回( 例如 + )還是傳引用返回(例如 +=)?
可以這麼說,所有需要返回一個Date類的函式都可以使用傳值返回,可是傳值返回在返回的過程中會生成一個臨時變數,並且會呼叫一次建構函式,開銷比較大,所以在可以使用傳引用返回的情況下,我們最好有限考慮傳引用返回。
傳引用返回的條件是,你要返回的Date變數在出了當前函式作用域還存在(例如 靜態變數static,或者是傳值傳進來的變數),只要生命週期大於這個函式的週期,就可以返回引用。當然還需要考慮這個變數應不應該被改變,例如使用 d1 + 1 的時候,d1是不需要被改變的,所以返回的值只可以是在類裡面建立的變數。使用 d1 += 1的時候,d1的值會被改變掉,所以就可以直接返回改變以後的d1
2.為了提高我們寫程式碼的效率,我們可以複用自己寫過的運算子
例如,我們已經寫好了一個 ' < '的運算子,當我們需要些 ‘ >= ’的時候就可以直接使用 ‘ !< ’,這樣寫不僅僅可以提高我們寫程式碼的效率,還可以提高我們修改程式碼的效率,如果你有100函式都是用的相同邏輯,呼叫的是一個基礎的函式,如果這個邏輯出錯,修改的時候就只需要該基礎函式的邏輯
3.區分前置++(--)和後置++(--)
相同點:兩者的運算子都是 ++,所以易於混淆
不同點:因為本身難以區分,所以編譯器幫了我們很大的忙,在呼叫++(--)運算子時,編譯器當然可以辨別程式設計師輸入的是前置還是後置,如果是後置,編譯器在傳參的時候就會傳一個 int 型別的變數,在呼叫的時候如果發現什麼引數都沒有,那就預設是前置++(--),如果發現引數中有一個 int 型別的形參,那麼就會處理成後置的++(--),但是這裡的 int形參什麼事情都不做,只是為了區分前置和後置
下面我們看一下完整程式碼:
//Date.h
#pragma once
class Date
{
public:
Date(int year = 1900,int month = 1,int day = 1);
~Date(){}
bool IsValid();
int GetMonthDay(int year,int month);
bool IsLeapYear(int year);
void Show();
Date& operator=(const Date& d);
bool operator==(const Date& d);
bool operator>=(const Date& d);
bool operator<=(const Date& d);
bool operator!=(const Date& d);
bool operator>(const Date& d);
bool operator<(const Date& d);
Date operator+(int day);
Date& operator+=(int day);
Date operator-(int day);
Date& operator-=(int day);
int operator-(const Date& d);//日期-日期 返回天數
Date& operator++();//預設前置
Date operator++(int);//用引數標誌後置++
Date& operator--();
Date operator--(int);
private:
int _year;
int _month;
int _day;
};
//date.cpp
#include "date.h"
#include <iostream>
#include <assert.h>
using namespace std;
Date::Date(int year,int month,int day):_year(year),_month(month),_day(day)
{
if(!IsValid()) // -> this.IsValid()
{
assert(false);
}
}
bool Date::IsValid()
{
return (_year > 0
&& _month > 0 && _month <= 12
&&_day > 0 && _day <= GetMonthDay(_year,_month));
}
int Date::GetMonthDay(int year,int month)
{
int arr[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
if(month == 2 && IsLeapYear(year))
{
++arr[2];
}
return arr[month];
}
bool Date::IsLeapYear(int year)
{
return ((year % 4 == 0 && year % 100 != 0)
|| year % 400 == 0);
}
void Date::Show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
// 運算子過載經歷以下幾個步驟
// (d1==d2)
// d1.operator==(d2)
// d1.operator==(&d1,d2)
// bool Date::operator==(Date* this,const Date& d)
bool Date::operator==(const Date& d)
{
if(_year == d._year && _month == d._month && _day == d._day)
return true;
return false;
}
//傳值返回:會多呼叫一次拷貝建構函式
//傳引用返回:直接返回,不需要呼叫拷貝構造
// 出了作用於變數還在,儘量使用傳引用返回
Date& Date::operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
bool Date::operator>=(const Date& d)
{
return !(*this < d);
}
bool Date::operator<=(const Date& d)
{
return ((*this < d) || (*this == d));
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
bool Date::operator>(const Date& d)
{
return !(*this <= d);
}
bool Date::operator<(const Date& d)
{
if((_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day))
return true;
return false;
}
Date Date::operator+(int day)
{
if(day < 0)
{
return (*this) - (-day);
}
Date d(*this);
d._day += day;
while(d.IsValid() == false)
{
int month_day = GetMonthDay(d._year,d._month);
d._day -= month_day;
++d._month;
if(d._month > 12)
{
d._month = 1;
++d._year;
}
}
return d;
}
Date& Date::operator+=(int day)
{
*this = (*this + day);
return *this;
}
Date Date::operator-(int day)
{
if(day < 0)
{
return (*this) + (-day);
}
Date d(*this);
d._day -= day;
while(d.IsValid() == false)
{
--d._month;
if(d._month == 0)
{
--d._year;
d._month = 12;
}
int pre_month_day = GetMonthDay(d._year,d._month);
d._day += pre_month_day;
}
return d;
}
Date& Date::operator-=(int day)
{
*this = (*this - day);
return *this;
}
int Date::operator-(const Date& d)//日期-日期 返回天數
{
int flag = 1;
Date max = (*this);
Date min = d;
if((*this) < d)
{
max = d;
min = (*this);
flag = -1;
}
int count = 0;
while(max != min)
{
++min;
++count;
}
return flag*count;
}
// ++d1 -> d1.operator++(&d1);
Date& Date::operator++()//預設前置
{
*this += 1; // 只調用一個函式
//*this = *this + 1; //呼叫兩個函式,還要呼叫拷貝建構函式
return *this;
}
// d1++ -> d1.operator++(&d1,0);
Date Date::operator++(int)//用引數標誌後置++
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}