目錄
前言
日期類的聲明.h
日期類的實現.cpp
獲取某年某月的天數
全缺省的構造函數
拷貝構造函數
打印函數
日期 += 天數
日期 + 天數
日期 -= 天數
日期 - 天數
前置++
后置 ++
前置 --
后置--
日期類中比較運算符的重載
<運算符重載
==運算符重載
!= 運算符重載
<=運算符重載
>運算符重載
>=運算符重載
=運算符重載
日期 - 日期
前言
????????在學習了類的6個默認成員函數后,我們現在動手實現一個日期類,以便鞏固所學知識。
日期類的聲明.h
#include<iostream>
using namespace std;
class Date
{
public:
// 獲取某年某月的天數
int GetMonthDay(int year, int month);
// 全缺省的構造函數
Date(int year = 1, int month = 1,int day = 1);
? // 拷貝構造函數
// d2(d1)
Date(const Date& d); ? ?
? ?// 賦值運算符重載
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
? ?// 析構函數
~Date();
//打印函數
void Print()const;
//<運算符重載
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);
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 前置--
Date& operator--();
// 后置--
Date operator--(int);
//日期-日期 返回天數
int operator-(const Date& d);
private:
int _year;
int _month;
int _day;
};
日期類的實現.cpp
獲取某年某月的天數
需要注意的地方有兩點:
? ? ? ? 1??為什么要用const static定義數組?
? ? ? ? 1.static:這意味著monthArray數組是一個靜態(tài)局部變量。靜態(tài)局部變量只在程序運行時初始化一次,并且它的生命周期將持續(xù)到程序結束,而不是每次函數調用時重新創(chuàng)建。在這個上下文中,這意味著無論這個GetMonthDay函數被調用多少次,monthArray數組都只會被初始化一次,提高了效率并節(jié)省了內存。
? ? ? ? 2.const 這表示monthArray數組是常量,其內容在定義后不可更改。由于數組存儲的是每個月的天數,這是一個固定不變的數據(除了二月可能因閏年而變化),所以聲明為const可以防止意外修改,并允許編譯器進行一些優(yōu)化。
?????????2??if判斷條件要先寫month == 2,判斷是否是2月,接著才去判斷是否是閏年。因為如果一個月不是二月,就沒必要判斷是否為閏年了。
圖解:
int Date::GetMonthDay(int year, int month)
{
const static int monthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if ((month == 2) // 0 1 2 3 4 5 6 7 8 9 10 11 12
&& ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
return monthArray[month];
}
????????綜合起來,const static int monthArray[13]
表示一個存儲每月天數的只讀數組,在整個程序執(zhí)行期間保持不變,而且在整個類內部可訪問。這樣設計既保證了數據的安全性,也提高了程序的運行效率。
全缺省的構造函數
? ?注意:當函數的聲明和定義分離時,我們給初始值的時候要在.h(聲明)去給,不能放到.cpp(定義)去給
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
//檢查日期是否合法
if (month < 1 || month>12
|| day<1 || day>GetMonthDay(year, month))
{
cout << "非法日期" << endl;
exit(-1);
}
}
拷貝構造函數
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
打印函數
void Date::Print()const
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
所以這個函數的作用:打印日期對象的信息,但并不改變日期對象的狀態(tài)。
日期 += 天數
- 若_day加了整數以后,<=該月的最大天數,則不需要修改,直接返回該日期
- 若_day加了整數以后,>=該月的最大天數,則用和之后的_day減去該月的最大天數,之后++_month
- 如果_month==13,則需要++_year,把_month置為1。如果_month未滿13,則重復第二步過程,直到不滿足循環(huán)條件為止。
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= (-day);
}
//_day是哪年哪月哪天的天數,day是要加的天數
_day += day;
while (_day > GetMonthDay(_year,_month))
{
//加完之后的日期天數,減了該月應當有的天數,之后++_month
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
++_year;
_month = 1;
}
}
return *this;
}
注意:當需要加的天數為負數時,則需要復用-=運算符重載。
日期 + 天數
? ? ? ? +和+=的區(qū)別在于,是否會改變操作數原本的值。
圖解:
? ? ? ? 還有一點需要注意的是,日期+=天數的返回值是引用&返回,由上面的圖解可以知道,+=操作符會改變操作數原來的值,所以+=運算符重載函數返回時,*this對象(傳進來的初始值)出了函數作用域還在,沒有被銷毀,使用引用提高效率。
? ? ? ? 但是+運算符不一樣,日期+天數不會改變原操作數的值,所以this指針指向的對象出了函數作用域就被銷毀了,不能使用傳引用返回。這時使用拷貝構造創(chuàng)建一個tmp對象,直接改變拷貝的那個對象tmp并返回,以傳值返回的方式返回。
圖解:
Date Date::operator+(int day)
{
Date tmp(*this);// 拷貝構造tmp,用于返回
tmp += day; // 復用operator+=
return tmp;
}
還有一點需要注意的是:為什么要用+復用+=,而不是+=復用+:
日期 -= 天數
? ? ? ? 對于-=運算符重載函數,進來先用初始值減掉要求的天數,若減去后得到的天數>0,則直接返回該日期。若減去后的天數<=0,則表明該日期不合法,需要調整,邏輯如下:
? ? ? ? 1.當_day<0時,--_month
? ? ? ? 2.若_month此時為0,則需要向年借位,--_year,并且重新把_month置為12,并將減去后得到的天數與該月應有的天數相加,除非_day>0,則需要像下圖一樣反復借位。
? ? ? ? ???若_month不為0,只需要將減去后得到的天數與該月應有的天數相加,直到_day>0,否則循環(huán)上述條件。
? ? ? ? 3.最后需要返回*this,跟+=運算符同理,this指向的對象出了作用域還在,使用傳引用返回。
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -(day);
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year,_month);
}
return *this;
}
注意:當需要減的天數為負數時,轉而調用+=運算符重載函數。
日期 - 天數
????????和+運算符的重載類似,-運算符的重載可以直接復用上面的-=運算符重載函數的實現。
Date Date::operator-(int day)
{
Date tmp(*this);// 拷貝構造tmp,用于返回
tmp -= day;// 復用operator-=
return tmp;
}
注意:-=運算符的重載函數采用的是引用返回,而-運算符的重載函數的返回值是傳值返回,因為 -運算符重載函數中的tmp對象出了函數作用域被銷毀了,所以不能使用引用返回。
前置++
? ? ? ? 直接復用+=運算符的重載函數
Date& Date::operator++()
{
*this += 1;// 復用operator+=
return *this;
}
后置 ++
? ? ? ? 我們可以看出前置++和后置++的運算符重載是及其相似的,為了區(qū)分,給個int作為占位符也同樣作為區(qū)分的標準,有參的是后置++,無參的為前置++。
Date Date::operator++(int)
{
Date tmp(*this);// 拷貝構造tmp,用于返回
*this += 1;// 復用operator+=
return tmp;
}
注意:后置++需要返回+1之前的值,調用拷貝構造創(chuàng)建的tmp對象保存++之前的初始值,接著再讓this指向的對象+1,返回tmp(對象+1之前的初始值),由此我們可知返回時應用傳值返回,不能用傳引用返回(出了作用域tmp就銷毀了)。
前置 --
? ? ? ? 無參的--為前置--,傳引用返回,直接復用前面的-=運算符的重載函數。
Date& Date::operator--()
{
*this -= 1;// 復用operator-=
return *this;
}
后置--
? ? ? ? 有參的--為后置--,傳值返回,直接復用前面的 -=運算符的重載函數。
Date Date::operator--(int)
{
Date tmp(*this);// 拷貝構造tmp,用于返回
*this -= 1;// 復用operator-=
return tmp;
}
日期類中比較運算符的重載
? ? ? ? 只需要實現<和==的運算符重載函數,其他的比較函數直接復用即可(賦值=運算符重載除外)。
<運算符重載
? ? ? ? 先判斷_year是否小于d._year,條件為true,則判斷_month是否小于d._month,對于_day同理。
這其中的繼續(xù)條件是在年相等或者月相等的條件下,繼而比較日是否小于,若不滿足條件則返回false。
bool Date::operator<(const Date&d)
{
if (_year < d._year)
{
return true;
}
if (_year == d._year && _month < d._month)
{
return true;
}
if (_year == d._year && _month == d._month && _day < d._day)
{
return true;
}
else
{
return false;
}
}
==運算符重載
? ? ? ? 若年月日均相等則條件為真,其中一個不等就為false。
bool Date::operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&&_day == d._day;
}
!= 運算符重載
? ? ? ? 這里復用了==運算符的重載函數,首先計算?*this == d
,即當前對象與傳入對象?d
?是否相等,然后對結果取反(!
),如果兩者原本相等,則結果為假(false),表示不相等;如果不相等,則結果為真(true),同樣表示不相等。
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
<=運算符重載
? ? ? ? 復用了<和==的運算符重載函數,條件為true只需滿足其中一個即可
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& Date::operator=(const Date& d)
{
if (*this != d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
日期 - 日期
????????找到兩個日期中的較大和較小者,然后通過不斷遞增較小的日期直到與較大的日期相等,計算出兩者之間的天數差,并根據初始比較結果確定正負號。
int Date::operator-(const Date& d)
{
Date max = *this;// 假設第一個日期較大
Date min = d;// 假設第二個日期較小
int flag = 1;// 此時結果應該為正值
if (*this < d)
{// 假設錯誤,糾正
max = d;
min = *this;
flag = -1;//改為負值
}
int n = 0;
while (min!= max)
{
++min;//較小的日期++
++n;//相差的總天數
}
return n * flag;
}
邏輯:
首先創(chuàng)建了兩個臨時變量?
max
?和?min
,將當前對象?*this
?的值賦給?max
,傳入參數?d
?的值賦給?min
。初始化一個整型變量?flag
?為1,這個標志位將在最后的結果中決定返回值的正負,表示是從max
日期到min
日期的方向。判斷當前對象?
*this
?是否小于傳入參數?d
。如果是,則交換?max
?和?min
?的值,并將?flag
?設置為 -1,這意味著我們要計算的是從較小的日期(min
)到較大的日期(max
)之間的天數差。初始化一個計數器?
n
?為0,用于記錄相差的天數。使用一個循環(huán)來遞增?
min
?直到它等于?max
。每次循環(huán)中,min
?會增加一天,并且計數器?n
?也會增加1,這樣就統(tǒng)計出了從?min
?到?max
?所經過的天數。循環(huán)結束后,返回?
n * flag
。由于之前已經通過?flag
?標記了方向,所以無論開始時是哪一天在前,都會得到正確的天數差。
??本文修改次數:0文章來源:http://www.zghlxwxcb.cn/news/detail-826850.html
??更新時間:2024年2月17日文章來源地址http://www.zghlxwxcb.cn/news/detail-826850.html
到了這里,關于【C++初階】第三站:類和對象(中) -- 日期計算器的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!