網站首頁 編程語言 正文
一、獲取某年某月的天數
1.在實現日期類的過程中,日期加減天數的應用場景一定會頻繁使用到這個函數接口,因為加減天數會使得月份發生變化,可能增月或減月,這個時候就需要在day上面扣除或增加當年當月的天數,所以這個接口非常的重要。
2.為了方便獲取到某年某月的天數,我們將數組大小設置為13,以便月份能夠和數組中的下標對應上,并且我們將數組設置為靜態,就不需要考慮每次調用函數建立棧幀后重新給數組分配空間的事情了,因為數組一直被存放在靜態區。
3.四年一閏,百年不閏,四百年一閏,閏年或平年會影響2月份的天數,所以我們要將這種情況單拉出來進行處理分析。
int GetMonthDay(int year, int month)
{
static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
else
{
return monthDayArray[month];
}
}
二、Date的默認成員函數(全缺省的默認構造)
1.編譯器默認生成的構造函數不會處理內置類型,所以我們需要自己去寫構造函數,非常推薦大家使用全缺省的構造函數,編譯器對自定義類型會自動調用該類類型的默認構造。
2.由于Date類的成員變量都是內置類型,所以析構函數不需要我們自己寫,因為沒有資源的申請。并且拷貝構造和賦值重載也不需要寫,因為Date類不涉及深拷貝的問題,僅僅使用淺拷貝就夠了。
3.至于取地址重載和const對象取地址重載,本身就不需要我們寫。
除非你不想讓別人通過取地址符號&來拿到實例化對象的地址,那可以返回nullptr,來屏蔽別人通過&拿到對象地址,但極大概率沒人這么做。
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
// 檢查日期是否合法
if (!(year >= 1&& (month >= 1 && month <= 12)&& (day >= 1 && day <= GetMonthDay(year, month))))
{
cout << "非法日期" << endl;
}
}
三、運算符重載
1.+ =、+、- =、-
1.實現+ =或 - =之后,就不需要實現+ -的重載了,我們可以調用之前實現過的成員函數,需要注意的是形參day有可能是負數,對于這種情況可以將其交給+=或-=對方來處理這種情況,因為這兩個運算符正好是反過來的,可以處理對方day為負數的時候的情況。
2.+=實現的思路就是,實現一個循環,直到天數回到該月的正常天數為止,在循環內部要做的就是進月和進年,讓天數不斷減去本月天數,直到恢復本月正常天數時,循環結束,返回對象本身即可。
3.-=實現的思路就是,實現一個循環,直到天數變為正數為止,在循環內部要做的就是借月和借年,讓天數不斷加上上一個月份的天數,直到恢復正數為止,循環結束,返回對象本身。
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= abs(day);
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
_month = 1;
++_year;
}
}
return *this;
}
Date Date::operator+(int day)
{
Date ret(*this);
ret += day;
return ret;
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += abs(day);
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
_month = 12;
--_year;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day)
{
Date ret(*this);
ret -= day;
return ret;
}
2.==、!=、>、>=、<、<=
1.下面這些比較運算符的重載應該是非常簡單的了,只需要實現一半的運算符重載即可,剩余運算符利用反邏輯操作符!即可輕松實現。
bool Date::operator==(const Date& d)const
{
return _year == d._year && _month == d._month && _day == d._day;
}
bool Date::operator>(const Date& d) const
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month >> d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
bool Date::operator>=(const Date& d) const
{
return *this > d || *this == d;
}
bool Date::operator<=(const Date& d) const
{
return !(*this > d);
}
bool Date::operator<(const Date& d) const
{
return !(*this >= d);
}
bool Date::operator!=(const Date& d) const
{
return !(*this == d);
}
3.前置++、–、后置++、–
1.實現前置和后置的區別就是,一個返回臨時對象,一個返回對象本身,在實現+=和-=以及+ -這些運算符重載之后,自增或自減運算符的重載非常簡單了,也是直接套用即可。
Date& Date::operator++()
{
return *this += 1;
}
Date Date::operator++(int)
{
Date ret(*this);
*this += 1;
return ret;
}
Date& Date::operator--()
{
return *this -= 1;
}
Date Date::operator--(int)
{
Date ret(*this);
*this -= 1;
return ret;
}
4.<<流插入、>>流提取(內聯的<<、>>重載函數)
1.流插入和流提取不適用于在類內部實現,因為隱含的this指針會先搶到第一個參數位置,而我們又習慣將cout作為左操作數使用,這就產生了沖突,所以我們需要將重載放到全局位置,并且我們很可能頻繁使用這兩個重載,所以最好搞成內聯函數。
2.起始流插入和流提取的重載非常簡單,本質上就是利用了庫中實現的類的實例化對象cin和cout,他們完全支持輸出編譯器的內置類型,而所有的自定義類型實際上都是內置類型堆砌而成,我們只需要在重載中將對象的內置類型一個個的輸出即可,這就是對象的流插入和流提取的本質思想。
inline ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
inline istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
四、兩個日期相減,返回天數
1.這個模塊的實現非常的有意思,利用了一個編程技巧假設,我們不知道哪個對象的日期更大一些,那我們就先假設一下,如果判斷錯誤,只要糾正一下即可。
然后定義一個計數器,讓較小日期自增,直到和較大日期相等為止,最后的計數器就是日期之間相差的天數,這個天數既有可能是正,也有可能是負,所以這里利用了flag標志位,返回flag和cnt的乘積。
int Date::operator-(const Date& d)const
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int cnt = 0;
while (min != max)
{
++min;
++cnt;
}
return cnt * flag;
}
五、日期類完整代碼
1.Date.h
#pragma once
#include <iostream>
using namespace std;
class Date
{
public:
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
int GetMonthDay(int year, int month)
{
//靜態數組,每次調用不用頻繁在棧區創建數組
static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
else
{
return monthDayArray[month];
}
}
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
// 檢查日期是否合法
if (!(year >= 1&& (month >= 1 && month <= 12)&& (day >= 1 && day <= GetMonthDay(year, month))))
{
cout << "非法日期" << endl;
}
}
//拷貝構造、賦值重載、析構函數都不用自己寫
void Print()const
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
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;
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);//后置--
// d1 - d2;
int operator-(const Date& d)const;
private:
int _year;
int _month;
int _day;
};
inline ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
inline istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
2.Date.cpp
#include "Date.h"
bool Date::operator==(const Date& d)const
{
return _year == d._year && _month == d._month && _day == d._day;
}
bool Date::operator>(const Date& d) const
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month >> d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
bool Date::operator>=(const Date& d) const
{
return *this > d || *this == d;
}
bool Date::operator<=(const Date& d) const
{
return !(*this > d);
}
bool Date::operator<(const Date& d) const
{
return !(*this >= d);
}
bool Date::operator!=(const Date& d) const
{
return !(*this == d);
}
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= abs(day);
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
_month = 1;
++_year;
}
}
return *this;
}
Date Date::operator+(int day)
{
Date ret(*this);
ret += day;
return ret;
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += abs(day);
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
_month = 12;
--_year;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day)
{
Date ret(*this);
ret -= day;
return ret;
}
Date& Date::operator++()
{
return *this += 1;
}
Date Date::operator++(int)
{
Date ret(*this);
*this += 1;
return ret;
}
Date& Date::operator--()
{
return *this -= 1;
}
Date Date::operator--(int)
{
Date ret(*this);
*this -= 1;
return ret;
}
int Date::operator-(const Date& d)const
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int cnt = 0;
while (min != max)
{
++min;
++cnt;
}
return cnt * flag;
}
3.Test.cpp
#include "Date.h"
void TestDate1()
{
Date d1(2022, 10, 8);
Date d3(d1);
Date d4(d1);
d1 -= 10000;
d1.Print();
Date d2(d1);
/*Date d3 = d2 - 10000;
d3.Print();*/
(d2 - 10000).Print();
d2.Print();
d3 -= -10000;
d3.Print();
d4 += -10000;
d4.Print();
}
void TestDate2()
{
Date d1(2022, 10, 8);
Date d2(d1);
Date d3(d1);
Date d4(d1);
(++d1).Print(); // d1.operator++()
d1.Print();
(d2++).Print(); // d2.operator++(1)
d2.Print();
(--d1).Print(); // d1.operator--()
d1.Print();
(d2--).Print(); // d2.operator--(1)
d2.Print();
}
void TestDate3()
{
Date d1(2022, 10, 10);
Date d2(2023, 7, 1);
cout << d2 - d1 << endl;
cout << d1 - d2 << endl;
}
void TestDate4()
{
Date d1, d2;
cin >> d1 >> d2;
cout << d1 << d2 << endl; // operator<<(cout, d1);
cout << d1 - d2 << endl;
}
int main()
{
//TestDate1();
TestDate4();
return 0;
}
原文鏈接:https://blog.csdn.net/erridjsis/article/details/128908483
相關推薦
- 2022-07-21 React生命周期
- 2022-04-24 C語言字符函數中的isalnum()和iscntrl()你都知道嗎_C 語言
- 2023-01-09 python數據分析之如何刪除value=0的行_python
- 2023-07-28 Cannot read properties of undefined (reading ‘push
- 2023-04-24 FFmpeg實戰之分離出PCM數據_C 語言
- 2023-02-26 pandas的apply函數用法詳解_python
- 2022-09-26 基數(桶)排序算法詳解之C語言版
- 2022-12-04 Android自定義View繪制貝塞爾曲線實現流程_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支