C++の初認識「クラス」:日付に関するクラスを書く(2つの日付間隔計算を添付)

7330 ワード

小さなディレクトリ
前言
本文
日付間隔の計算
日付後押し1日の関数:tomorrow
その他のメンバー関数
もう一つの考え方で書かれたtomorrow
展示機能用main関数
前言
C++クラスの勉强を始め、先生が出した宿题は日付を书くクラス--MyDateです.
最初のジョブでは、次の関数が必要です.
void set(int, int, int);//3つの値でクラスを初期化
void set(const MyDate& date);//別のMyDateクラスへの通常参照で初期化
void print();//日付の印刷
int equals(const MyDate& date);//日付が等しいかどうかを判断する
void tomorrow();//現在の日付を1日後回しにする
これらを除いて、自分が事前に授業を見たので、また2つの構造関数を書きました.tomorrowを実現するために閏年の判断を用いてif_と書きましたleap_year();同時に、自分が考えている機能をいくつか追加し、最終的には以下のようにします.
class MyDate
{
private:
    int  year, month, day;
public:
    void set(int y_, int m_, int d_);
    void set(const MyDate& date);
    void print();
    int  equals(const MyDate& date);
    void tomorrow();
    int days(int, int);
    int if_leap_year()
    { 
        if( (year % 4 ==0 && year % 100 != 0) || year % 400 == 0 ) return 1;
        else return 0;
    }
    int if_leap_year(int year)
    {
        if( (year % 4 ==0 && year % 100 != 0) || year % 400 == 0 ) return 1;
        else return 0;
    }
    int compare(const MyDate & dst)
    {
        if (1000 * year + 100 * month + day > 1000 * dst.year + 100 * dst.month + dst.day) return 1;
        else if (equals(dst) == 1) return 0;
        else return -1;
    }
    int get_gap(const MyDate& dst);
    int gap(const MyDate& dst);
    MyDate();
    MyDate(int y_, int m_, int d_);
};

このうちcompareは、2つの日付間の前後関係を判断する関数である.if_leap_yearは閏年を判断する関数である.gapとget_gapは日付間隔を求める関数である.
本文
日付間隔の計算
自分は中学校の时にコンピューターコンテストに少し触れたことがあります.基础文法を勉强した后、一日暇で无事(実は宿题を书くことができなくてパソコンを游びたいです)プロセス向けの日付间隔计算プログラムを书きました.その本质は日数を分けて计算して和を求めます.つまり、まず2つの日付が同年なのか年越しなのかを判断します.さらに状況に応じて議論し計算する.今日宿題をする時、かつて書いたこの小さいプログラムを思い付いて、インターネットを利用して探して、私のこのような愚かな方法を見ていないようで、そこで記念に出したいと思っています.
毎月の日数を簡単に取得するために、指定した年月の合計日数を返す2つのパラメータを持つdays(int,int)関数を書きました.
int MyDate::days(int y, int m)
{
    int days[13] ={0,31,28,31,30,31,30,31,31,30,31,30,31};
    if (m==2)
    {
        if(isLeap(y)) return 29;
        else return 28;
    }
    else return days[m];
}

以下はクラスにカプセル化されたgap()関数で、コードシートの注釈に構想が書かれています.
ここでcy,cm,cdのcは「current」を表し、「現在」を意味する.同様にeは「expected」であり、「目標」の日付を指す.
また、days()関数を呼び出すたびにオーバーヘッドが発生すると思う場合は、gap()関数に毎月の日数を格納する配列を設定し、必要に応じて年の変化時に2月の日数に関するデータを更新することも考えられます.
int MyDate::gap(MyDate& dst)
{
    int cy = year, cm = month, cd = day;
    int ey = dst.year, em = dst.month, ed = dst.day;
    int sum = 0;
    if (compare(dst)==1)
    {
        swap(cy,ey); swap(cm,em); swap(cd,ed);
    }
    if (ey == cy)
    {
        if (em == cm) sum = ed - cd; //    ,       
        if (em > cm) //     
        {
            sum += (days(cy,cm) - cd); //       ,
            sum += ed; //         ,
            for (int i = cm + 1; i < em; i++) sum += days(cy,i);
            //        ,  sum!
        }
    }
    if (ey > cy)
    {
        //           
        //1.           
        sum += (days(cy,cm) - cd); 
        //2.       ,                
        for (int i = cm + 1; i <= 12; i++) sum += days(cy,i);
        //3.           
        for (int i = cy + 1; i < ey; i++) 
        {
            if (isLeap(i)==1) sum += 366;
            else sum += 365;
        }
        //4.                     
        for (int i = 1;i < em; i++) sum += days(ey, i);
        //5.         
        sum += ed;
    }
    return sum;
}

注意:デバッグ中に自分が前に書いたコードに小さな問題があることに気づきました.同じ考え方で書き直したバージョンで、比較的わかりやすくなっています.
デバッグ用のmain()関数を添付します.
int main()
{
    MyDate now(2020,3,12);
    MyDate dst(2020,3,12);
    for (int i=0; i<2000; i++)
    {
        now.print();
        cout<

このプロセス向けのプログラムは少し長い(しかし、実行速度は速い)ことがわかります.宿題を終えてtomorrow()にヒントを得た--なぜ「数日」のアルゴリズムを極致に発揮しないのか.equals()を考えると、両者がうまく協力していることがわかり、while文1つで反復操作を完了することができます!すると次のようになります.
int MyDate::get_gap(const MyDate& dst)
{
    int gap = 0;
    MyDate now(year,month,day);
    MyDate tgt(dst);
    if (compare(dst) == 1) 
    {
        while (tgt.equals(now)==0)
        {
            tgt.tomorrow();
            gap++;
        }
    }
    else 
    {
        while (now.equals(tgt)==0)
        {
            now.tomorrow();
            gap++;
        }
    }
    return gap;
}

注意:追加されたif、else文は、現在の日付よりも前の日付が入力された場合を考慮するためです.そうすると、この反復プロセスを逆に実行する必要があります.
main()関数でget_を呼び出すgap()とgap()関数:
int main()
{
    MyDate now(2020,3,12);
    MyDate dst(2099,3,12);
    cout<

もちろん、第2の方法は第1の方法ほど速くないに違いないが、単回の計算時間が長くて気づきにくい.また、2つ目は簡単に書けます.
日付後押し1日の関数:tomorrow
ここでtomorrow関数を紹介します.この関数は「キャリー」の考え方を採用すれば、複雑なif文の議論を避けることができます.
まず日付を+1して、日付が現在の月の最大日数を超えているかどうかを見ます.
もしそうなら、月数+1、日付を1日に変更します.
月が12を超えたかどうかを見て、もしそうなら、年+1、月を1月に変更します.
これにより、tomorrowの機能が実現します.
void MyDate::tomorrow()
{
    int days[13] ={0,31,28,31,30,31,30,31,31,30,31,30,31};
    if(if_leap_year()) days[2]=29;
    else days[2] =28;
    day++;
    if (day > days[month]) {
        day = 1;
        month++;
        if(month > 12) 
        {
            month = 1;
            year++;
        }
    }
}

その他のメンバー関数
次に、他のメンバー関数のマスターを示します.
void MyDate::set(int y_, int m_, int d_)
{
    year = y_; month = m_; day = d_;
}
void MyDate::set(const MyDate& date)
{
    year = date.year;
    month = date.month;
    day = date.day;
}
void MyDate::print()
{
    cout<

もう一つの考え方で書かれたtomorrow
ここにif条件文で書かれたtomorrow関数を置きます.実は本質的には上のtomorrow関数と同じで、分類討論です.一部の学生は違う書き方をしていて、書き方がたくさんあって、ここでは展示しません.
void tomorrow()
{
	if(month==2) //feburary
	{
		int flag;
		if(isleap()) flag = 1;
		else flag = 0;
		day++;
		if(day>(28+flag)) { month++; day=1; }
	}
	else if((month<8 && month%2==1)||(month>=8&&month%2==0)) // 1,3,5,7,8,10,12
	{
		day++;
		if(day>31) { day=1; month++; }
	}
	else //if(month==4||month==6||month==9||month==11) //4,6,9,11
	{
		day++;
		if(day>30) { day=1; month++; }
	}
	if(month>12) { month=1; year++; }
}

if条件文を使用するには論理的な問題に注意する必要があることに注意してください.
間違いやすいところがあり、ある状況を議論した後、month++(月に変化があった)がreturnという関数がないため、次の状況に入ることができた.
例えば、2013年11月30日にtomorrowが実行され、最初のif文が実行されてから12月1日になり、その後、条件を満たして次の判断分岐に入り、12月2日になります.
実は頭のいいあなたはここを見て、問題がどこにあるか知っているはずです.このような場合はif条件並列の構造を用いることが一般的であり,言い換えれば,これらの条件が描かれると,1点多の場合ではなく,複数の敷居(奇妙な比喩)を順次アクセスするようになるが,問題は,ある条件に最初から入った後,条件判断に関連する数値が変化し,また別の分岐に入るようになることである.プログラム実行プロセスは線形であるにもかかわらず、このような可能性は依然として存在する.(switch文の後ろのbreakを連想します;)
ここを見た読者は、return文を使用したり、if文の構造を書き換えたりすることができます.
展示機能用main関数
最後に、先生の作業要求(プログラム機能を示す)を実現するmain()関数です.
int main()
{
    //MyDate d1(2015,12,31);
    //MyDate d2(d1);
    MyDate d1,d2;
    d1.set(2015, 12, 31);
    d2.set(d1);
    d1.print();
    cout << endl;
    d2.print();
    cout << endl;
    cout << "d1.equals(d2)?" << d1.equals(d2) << endl;
    //equals    d1 d2    ,  、 、       1;    0
    d1.print();
    cout << "    :";
    d1.tomorrow();
    d1.print();
}