コンテンツ
6つのデフォルトのメンバー関数を 学習した後、日付クラスを完了することができます。通常、100日後に何個になるかを計算する必要がありますか?今日は何曜日ですか?XXXから何日経ちましたか?等々。これらのメンバー関数を実装するには、カスタムタイプに依存する必要があります。
まず、メンバー関数とメンバー変数の宣言を行います
#pragma once
#include<iostream>
#include<stdbool.h>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1);//声明
void Print()const;//打印
int GetMonthDay(int year, int month)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;//>=运算符重载
bool operator<=(const Date& d)const;//<=运算符重载
Date& operator+=(int day);//加等于
Date operator+(int day)const;//加
Date& operator-=(int day);//减等于
Date operator-(int day)const;//减
Date& operator++();//前置++
Date operator++(int);//后置++
Date& operator--();//前置--
Date operator--(int);//后置--
int operator-(const Date& d)const;//日期-日期
void PrintWeekDay()const;//判断星期几
private:
int _year;
int _month;
int _day;
};
コンストラクターの初期化
私たちが遭遇した最初の問題は、日付が与えられた場合、その日付の合理性と存在を判断する必要があるということです。
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
//判断传入时间的合法性,例如2022-13-27
if (!(_year > 0
&& (_month > 0 && _month < 13)
&& (_day > 0 && _day <= GetMonthDay(_year, _month))))
{
cout << "非法日期:" << endl;
Print();
}
}
int Date::GetMonthDay(int year, int month)const//获取这年某月的天数
{
static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = days[month];
//闰年判断:四年一闰,百年不闰,四百又闰
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
day += 1;
}
return day;
}
GetMonthDayの問題について書いてください:
最初の問題はうるう年問題です。今年と今月の日数を取得する必要があり、必然的にうるう年の判断の問題が発生します。
①うるう月を判断するために、12のifelseステートメントを使用できます
②switchcaseステートメントを使用できます
③上記のコードは冗長なようです。12か月間の各月の日数は誰もが知っているので、これらの月を静的配列に格納できます。ここで、添え字は0、初期化は0、残りの月はすばやく書くことができます
2つ目の問題は、2月(月== 2)かどうかを最初に判断できることです。2月でない場合は、うるう年かどうかを判断する必要がないためです。
印刷機能
標準出力を直接使用できます
//打印函数
void Date::Print()const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
日付クラスのサイズ比較
クラスのメンバー関数、デフォルトの最初のパラメーターは非表示のthisポインターであり、2番目のパラメーターは右のオペランドであることに注意してください。
>演算子のオーバーロード
考え方は比較的単純で、年は大きく、年は月よりも大きく、月は大きく、月は空よりも大きく、空は空よりも大きい
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;
else
return false;
}
==演算子のオーバーロード
等しいとは、2つの日付が等しい場合、両方が等しいことを意味します
bool Date:: operator==(const Date& d)const//等于
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
>=演算子のオーバーロード
日付は以上である必要があります
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);
}
日付操作
日付+=日数
私たちの頭に浮かぶ最初のことは間違いなくキャリーの問題です。まず、その日に日数を加算し、その日付が合法かどうかを検討します。違法の場合は、丸めの問題を検討します。
キャリーの問題:
1.空がいっぱいになる月に切り上げます(空がいっぱいの場合は、現在の月の日数を減算し、月に1を加算します)
2.満月のときに前年を引き継ぎます(満月の場合は、年に1を追加し、月を1にリセットします)
* thisを返します:
+ =は2つのオペランド記号であり、左側のオペランドも返す必要があります。*これは実際にはdオブジェクトが更新された後の日付です。
参照は次を返します:
値のコピーを減らすために、*これは実際にはdのエイリアスであり、直接返すことができます
特別な場合、加算が負の日数である場合、-=現在の日数の負の値になります。
Date& Date::operator+=(int day)//加等于
{
if (day < 0)//当day为负数时,处理一下
{
return *this -= -day;
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
return *this;
}
日付+日
+と+=の違いが戻り値です。
例:d1 + 10はd1の値を変更しませんが、d1 +=10はd1の値を変更します
Date Date::operator+(int day)const//加
{
Date ret(*this);//运用拷贝构造
ret += day;//复用已经实现的 +=
//实际上的编译器会这样处理
//ret.operator+=(day);
return ret;
}
日付-=日数
私たちが最初に頭に浮かぶのは、借り入れの問題です。まず、その日から日数を引いて、その日付が合法かどうかを判断します。合法でない場合は、借入問題を考慮する必要があります。
辞任の質問:
1.日が負の数の場合、月は-1である場合は減算します
2.月が0に短縮された場合(month == 0)、前の年から借用する必要があり、年は-1になり、月は12にリセットされます。
3.最終日とその月の日数
特別な場合、負の日数を引くと、+=現在の日数の負の値になります。
Date& Date::operator-=(int day)//减等于
{
if (day < 0)//当day为负数时,处理一下
{
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)const//减
{
Date ret(*this);
ret -= day;
return ret;
}
Pre-++とpost-++の最大の違いは、戻り値の違いです。Pre-++は加算後の値を返し、post-++は加算前の値を返します。
C ++のpre-operatorとpost-operatorを区別するために、post ++にパラメータープレースホルダーを導入して、これら2つの関数のオーバーロードを区別します。これは、実用的な意味はありません。
注: post ++は、加算前に値を返す必要があります。最初に* thisを使用して、retオブジェクトをコピーして作成します(実際には、加算前に値のコピーを保存します)。retオブジェクトはスコープ外であるため、破棄されるため、参照によって返すことはできませんが、パラメータを渡すことによってのみ返すことができます。これは、コピーをDateに再度コピーすることと同じです。事前追加により、参照を直接返すことができ、コピーを減らすことができます。
プレフィックス++
Date& Date::operator++()//前置++,返回加加后的值
{
*this += 1;
return *this;
}
投稿++
Date Date::operator++(int)//后置++,返回加加前的值
{
Date ret(*this);//拷贝构造
*this += 1;
return ret;
}
事前--
Date& Date::operator--()//前置--
{
Date ret(*this);//拷贝构造
*this -= 1;
return *this;
}
後方 -
Date Date::operator--(int)//后置--
{
Date ret(*this);//拷贝构造
*this -= 1;
return ret;
}
日付-日付
日常生活の中で、2つの日付の間に何日あるかを計算する必要があるかもしれません。ここで計算できます。
アイデア:小さい日付を選択し(1を追加)、それを使用して大きい日付に「追いつく」ことができます。次に、小さい日付が追加されるとそれ自体が追加されるカウント変数を定義して、それに追いつくことができます。 。その後、2日間の違い
int Date::operator-(const Date& d)const//日期-日期
{
//我们不知道哪个日期大一点,所以假设
Date max = *this;//先假设d1>d2
Date min = d;
int flag = 1;
if (*this < d)//如果d1<d2,再交换最大值和最小值
{
max = d;
min = *this;
flag = -1;
}
int count = 0;
while (min != max)
{
++min;
++count;
}
return count * flag;
}
曜日を印刷する
私たちは時々私たちの生活の中でこの日付の曜日を見つける必要があります、そして今私たちはそれをすることができます。
アイデア:検索したところ、1900年1月1日が月曜日であることがわかりました。これを開始点として使用し、毎週配列に格納して、特定の日付と1900〜1-1の差を計算できます。違いは、最終的に取得される日数は、曜日を知るために7を法とするものです。
void Date::PrintWeekDay()const
{
const char* arr[] = { "星期一","星期二","星期三","星期四","星期五","星期六","星期日" };
/*Date start(1900, 1, 1);
int count = *this - start;*/
//匿名对象
int count = *this - Date(1900, 1, 1);
cout << arr[count % 7] << endl;
}
見てくれてありがとう!