欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++日期類的實(shí)現(xiàn)日期計(jì)算器舉例詳解

 更新時(shí)間:2024年05月15日 10:12:18   作者:唉蘇菲夫婦  
這篇文章主要給大家介紹了關(guān)于C++日期類實(shí)現(xiàn)日期計(jì)算器的相關(guān)資料,我們要考慮日期的增加和減少,自增和自減,以及兩個(gè)日期類的比較,以及當(dāng)前日期類的日期顯示和用戶的輸入輸出,需要的朋友可以參考下

前言

1.日期類是一種十分經(jīng)典的類型。對(duì)于C++的初學(xué)者,它能夠幫助我們?nèi)跁?huì)貫通許多C++的基礎(chǔ)知識(shí),它涉及許多的基礎(chǔ)語(yǔ)法,比如引用,函數(shù)重載,傳值/傳參返回,構(gòu)造函數(shù),運(yùn)算符重載,const成員等等。

如果有不了解的,可以前往我的主頁(yè)瀏覽相關(guān)文章。

日期計(jì)算器可以實(shí)現(xiàn)兩個(gè)日期的比較,兩個(gè)日期的相減,日期的加減天數(shù)等有意義的運(yùn)算。

2.本文依然采用多文件方式。其中:

Date.h //定義類,存放各函數(shù)的聲明;Date.cpp //實(shí)現(xiàn)各重載函數(shù);Test.cpp //測(cè)試各函數(shù)的功能。

在C++中,由于函數(shù)的聲明與定義分離,如果要定義成員函數(shù),就要指定類域,這是基本語(yǔ)法。

一,各個(gè)函數(shù)功能的實(shí)現(xiàn)

1. 檢查輸入的日期是否合法

不管是日期的比較還是日期的運(yùn)算,第一步都要檢查日期的合法性。特別是月份和每個(gè)月的天數(shù)。

代碼實(shí)現(xiàn)如下:

bool Date::CheakDate()
{
	if (_month < 1 || _month>12
		|| _day<1 || _day>GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

2. 構(gòu)造函數(shù) (初始化函數(shù))

為了方便,在使用默認(rèn)構(gòu)造函數(shù)時(shí),一般是自己顯式的實(shí)現(xiàn)一個(gè)全缺省構(gòu)造函數(shù)。

注意:在函數(shù)的聲明和定義分離時(shí),如果要給缺省值,必須在函數(shù)聲明的時(shí)候給。

代碼實(shí)現(xiàn)如下:

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;

     //日期的源頭,是從構(gòu)造函數(shù)里出來的,所以要在這里判斷
	if (!CheakDate())
	{
		cout << "日期非法!" << endl;
	}
}

二,比較類的運(yùn)算符重載

3. <運(yùn)算符重載

判斷兩個(gè)日期誰(shuí)更小。思路:先比年,年小就小,年相等比月,月小就小,年月相等比日,日小就小。

代碼實(shí)現(xiàn)如下:

d1 < d2 隱含的this指針是d1,d是d2的別名。

bool Date::operator< (const Date& d) const
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			return _day < d._day;
		}
	}

	return false;
}

4. ==運(yùn)算符重載

判斷兩個(gè)日期是否相等 。這個(gè)比較簡(jiǎn)單,如果兩者的年月日都相等,即相等。

代碼實(shí)現(xiàn)如下:

bool  Date::operator==(const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

5. >=運(yùn)算符重載

有人可能會(huì)仿照<運(yùn)算符重載的方法,使用復(fù)雜的邏輯,寫各種晦澀的代碼實(shí)現(xiàn)。其實(shí)只要實(shí)現(xiàn)了<運(yùn)算符重載和==運(yùn)算符重載,下面的日期比較類都是可以復(fù)用的。 比如這里的>=,< 取反就是>=。

代碼實(shí)現(xiàn)如下:

bool Date::operator>= (const Date& d) const
{
	return !(*this < d);
}

6. >運(yùn)算符重載

<= 取反,就是>。

bool Date::operator> (const Date& d) const
{
	return !(*this <= d);
}

7. <=運(yùn)算符重載

只要滿足<或者=,就是<=。

bool Date::operator<= (const Date& d) const
{
	return *this < d || *this == d;
}

8. !=運(yùn)算符重載

==去取反,就是!=

bool  Date::operator!=(const Date& d) const
{
	return !(*this == d);
}

9. 獲取某月的天數(shù)

這個(gè)函數(shù)是整個(gè)日期類的關(guān)鍵,也是最頻繁調(diào)用的一個(gè)函數(shù)。由于這個(gè)原因,最好把它定義成內(nèi)聯(lián)函數(shù),避免每次調(diào)用都要開辟空間,可以提升效率。根據(jù)C++的語(yǔ)法,定義在類里默認(rèn)是內(nèi)聯(lián),inline可加可不加

代碼實(shí)現(xiàn)如下:

這里還有兩個(gè)優(yōu)化的細(xì)節(jié):

1. month == 2 和后面的取模運(yùn)算的位置。首先滿足是2月,再判斷是否是閏年,效率會(huì)更高。2. static的使用,由于該函數(shù)頻繁調(diào)用,把數(shù)組放在靜態(tài)區(qū),避免每次調(diào)用函數(shù)時(shí)每次都要開辟數(shù)組空間。

int GetMonthDay(int year, int month)
{
    //斷言,確保輸入月份的有效性
    assert(month > 0 && month < 13);

    //枚舉出月份的天數(shù)
   static int monthDayArray[13] = { -1, 31,28,31,30,31,30,31,31,30,31,30,31 };

    //判斷2月的平年和閏年
    if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
    {
        return 29;
    }
    else
    {
        return monthDayArray[month];
    }
}

三,運(yùn)算類的重載

10. 日期+=天數(shù)

比如d1 + 50,這里的d1已經(jīng)改變了。

計(jì)算過程如下:

注意,每次超過月份天數(shù)后,是減當(dāng)前月的天數(shù)。

代碼實(shí)現(xiàn)如下:

Date& Date::operator+=(int day)
{
	//這里是處理有人傳負(fù)的天數(shù),轉(zhuǎn)化成調(diào)用-=函數(shù)
	if (day < 0)
	{
		return *this -= -day;
	}

	//先加上天數(shù)
	_day += day;

	//加上天數(shù)后超出了月的范圍
	while (_day > GetMonthDay(_year, _month))
	{
		//減去當(dāng)前月的天數(shù),此時(shí)月份+1
		_day -= GetMonthDay(_year, _month);
		++_month;

		//超過12個(gè)月時(shí)
		if (_month == 13)
		{
			++_year;//年份+1
			_month = 1;//別忘了月份還要從1月開始
		}
	}
	return *this;
}

11. 日期 + 天數(shù)

比如 d1 + 50,d1沒有改變。

代碼實(shí)現(xiàn)如下:

Date Date::operator+(int day) const
{
    //實(shí)例化一個(gè)臨時(shí)的局部變量,用拷貝構(gòu)造
    //把d1的日期拷貝給tmp,這樣d1就不會(huì)改變
	Date tmp = *this;
	tmp += day;//直接復(fù)用+=

	//注意:出了這個(gè)函數(shù),tmp會(huì)被銷毀,所以這里不能用引用返回。
	//	    這里是傳值返回,所以會(huì)形成一個(gè)拷貝
	return tmp;
}

12. 日期-=天數(shù)

比如 d1- 50,這里的 d1也改變了。計(jì)算過程如下:

注意,這里加(借)的是下一個(gè)月的天數(shù)。

代碼實(shí)現(xiàn)如下:

Date& Date::operator-=(int day)
{
    //這里是處理有人傳負(fù)的天數(shù),轉(zhuǎn)化成調(diào)用+=函數(shù)
	if (day < 0)
	{
		return *this += -day;
	}

	_day -= day;

	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}

		//借上一個(gè)月的天數(shù)
		_day += GetMonthDay(_year, _month);
	}

	return *this;

13. 日期 - 天數(shù)

思路同 日期 + 天數(shù)。

代碼實(shí)現(xiàn)如下:

Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;

	return tmp;
}

四,前置,后置類的重載

首先要知道前置和后置運(yùn)算的區(qū)別:

前置:返回運(yùn)算后的值;

后置:返回運(yùn)算前的值。

其次,還要理解函數(shù)重載和運(yùn)算符的重載:

函數(shù)重載:可以讓函數(shù)名相同,參數(shù)不同的函數(shù)存在;運(yùn)算符重載:讓自定義類型可以用運(yùn)算符,并且控制運(yùn)算符的行為,增強(qiáng)可讀性 。

這兩者各論各的,沒有關(guān)系。但是,多個(gè)同一運(yùn)算符重載可以構(gòu)成函數(shù)重載。

我們知道,前置和后置是同一運(yùn)算的不同形式 ,但是他們的函數(shù)名相同,參數(shù)都是隱含的this參數(shù),無(wú)法構(gòu)成重載同時(shí)存在。所以為了區(qū)分,并且構(gòu)成重載,C++規(guī)定:強(qiáng)行給后置(后置++和后置- -)函數(shù)的參數(shù)增加了一個(gè) int 形參,不需要寫形參名。并且這個(gè)形參沒有任何意義。

14. 前置++

前置++先加,后用,返回的是加之后的值,可以直接復(fù)用+=運(yùn)算符重載,返回的是改變后的 *this。

Date& Date::operator++()
{
	*this += 1;
	return *this;
}

15. 后置++

注意:后置函數(shù)多一個(gè)形參 int,以便與前置構(gòu)成重載。后置++是先用,后加,返回的是加之前的值。所以需要?jiǎng)?chuàng)建一個(gè)臨時(shí)的局部對(duì)象 tmp,用拷貝構(gòu)造把原來的 *this 拷貝給 tmp 。最后返回 tmp。

Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}

16. 前置 - -

前置- -和前置++的原理類似。

Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

17. 后置 - -

注意:后置函數(shù)多一個(gè)形參 int,以便與前置構(gòu)成重載。原理與后置++類似。

Date Date::operator--(int) 
{
	Date tmp(*this);
	*this -= 1;

	return tmp;
}

注意:

  • 前置和后置運(yùn)算,一般建議用前置,因?yàn)楹笾妙愋枰截悩?gòu)造,傳值返回,這就會(huì)產(chǎn)生兩次拷貝和一次析構(gòu),而前置卻沒有這樣的消耗,相比之下前置類有優(yōu)勢(shì)

18. 日期-日期 返回天數(shù)

兩個(gè)日期相減,返回的是相差的天數(shù),是一個(gè)整形。思路:找出大的年份和小的年份,再定義一個(gè)計(jì)數(shù)器和小的年份一起++,直到和大的年份相等。

比如 d1 - d2

代碼實(shí)現(xiàn)如下:

          //隱含的this指針是d1,d是d2的別名
int Date::operator-(const Date& d) const
{
   //先假設(shè)大日期和小日期
	Date max = *this;
	Date min = d;
	
	//默認(rèn)假設(shè)正確
	int flag = 1;
    
    //如果假設(shè)錯(cuò)誤,就進(jìn)行改正
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	//讓計(jì)數(shù)n和小的日期一起加,加到和大的日期相等
	while (min != max)
	{
		++min;
		++n;
	}
    
    //flag的正負(fù)有妙用
	return n * flag;
}

五,完整代碼

Date.h

#pragma once

#include <iostream>
using namespace std;
#include <assert.h>
#include <stdbool.h>
    
class Date
{
     //構(gòu)造函數(shù)
    Date(int year, int month, int day);
    void Print() const;
     
     //定義為內(nèi)聯(lián)函數(shù)
    int GetMonthDay(int year, int month)
    {
        //斷言,確保輸入月份的有效性
       assert(month > 0 && month < 13);

       static int monthDayArray[13] = { -1, 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];
        }
    }

    //檢查日期的合法性
    bool CheakDate();

    //兩個(gè)日期之間的比較
    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;

    //d1 += 100,d1已經(jīng)改變
    Date& operator+=(int day);
    Date& operator-=(int day);

    //d1 + 50,d1不變
    Date operator+(int day) const;
    Date operator-(int day) const;

    // d1 - d2
    int operator-(const Date& d) const;

    // ++d1 -> d1.operator++()
    Date& operator++();

    // d1++ -> d1.operator++(1) 整數(shù)任意給
    Date operator++(int);

    //前置,后置--
    Date& operator--();
    Date operator--(int);

private:
    int _year;
    int _month;
    int _day;
};

Date.cpp

#define _CRT_SECURE_NO_WARNINGS 

#include "Date.h"

bool Date::CheakDate()
{
	if (_month < 1 || _month>12
		|| _day<1 || _day>GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

//1.缺省參數(shù)只能在聲明的時(shí)候給
//2.成員函數(shù)聲明與定義分離時(shí),要指定類域
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;

	if (!CheakDate())
	{
		cout << "日期非法!" << endl;
	}
}

void Date::Print() const
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

//思路:先比年,年小就小,年相等比月,月小就小,年月相等比日,日小就小
//d1 <d2 隱含的this是d1, d是d2的別名
bool Date::operator< (const Date& d) const
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			return _day < d._day;
		}
	}

	return false;
}

//先寫好大于和等于 或者 小于和等于的函數(shù),其余的進(jìn)行復(fù)用
//d1 <=d2
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 _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

bool  Date::operator!=(const Date& d) const
{
	return !(*this == d);
}


//日期 += 天數(shù) :d1 + 100
//這里的d1 已經(jīng)改了
Date& Date::operator+=(int day)
{
	//這里是處理有人傳負(fù)的天數(shù)
	if (day < 0)
	{
		return *this -= -day;
	}

	//先加上天數(shù)
	_day += day;

	//加上天數(shù)后超出了月的范圍
	while (_day > GetMonthDay(_year, _month))
	{
		//減去當(dāng)前月的天數(shù),此時(shí)月份+1
		_day -= GetMonthDay(_year, _month);
		++_month;

		//超過12個(gè)月時(shí)
		if (_month == 13)
		{
			++_year;//年份+1
			_month = 1;//別忘了月份還要從1月開始
		}
	}
	return *this;
}


// d1 + 50,d1沒有改變
Date Date::operator+(int day) const
{
    //實(shí)例化一個(gè)臨時(shí)的局部變量,用拷貝構(gòu)造,把d1的日期拷貝給tmp,這樣d1就不會(huì)改變
	Date tmp = *this;
	tmp += day;//直接復(fù)用+=

	//注意:出了這個(gè)函數(shù),tmp會(huì)被銷毀,所以這里不能用引用返回。
	//	    這里是傳值返回,所以會(huì)形成一個(gè)拷貝
	return tmp;
}

//日期 -= 天數(shù) :d1 - 100
//這里的d1 已經(jīng)改了
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}

	_day -= day;

	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}

		//借上一個(gè)月的天數(shù)
		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;

	return tmp;
}


// ++d
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//這兩種++ 建議用前置++,因?yàn)楹笾?+會(huì)產(chǎn)生兩次拷貝和一次析構(gòu),相比之下前置++有優(yōu)勢(shì)。
//d++
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}


//--d
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

//d--
Date Date::operator--(int) 
{
	Date tmp(*this);
	*this -= 1;

	return tmp;
}

//思路:找出大的年份和小的年份,再定義一個(gè)計(jì)數(shù)器和小的年份一起++,直到和大的年份相等。
//d1 - d2
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 n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

Test.cpp

#define _CRT_SECURE_NO_WARNINGS 

#include "Date.h"

void TestDate1()
{
	
	Date d1(2024, 4, 14);
	Date d2 = d1 + 5000;
	d1.Print();
	d2.Print();

	Date d3(2024, 4, 14);
	Date d4 = d3 - 5000;
	d3.Print();
	d4.Print();

	Date d5 (2024, 4, 14);
	d5 += -5000;//轉(zhuǎn)化成-=運(yùn)算,計(jì)算5000天之前的時(shí)間
	d5.Print();
}

void TestDate2()
{
	Date d1(2024, 4, 14);
	Date d2 = ++d1;
	d1.Print();
	d2.Print();

	Date d3 = d1++;
	d1.Print();
	d3.Print();

}

int main()
{
	TestDate1();

	return 0;
}

日期的比較類比較簡(jiǎn)單,不在這里示范,讀者自行驗(yàn)證。

比如,調(diào)用TestDate1()計(jì)算未來的日期和以前的日期:

再比如,調(diào)用TestDate2()觀察前置與后置運(yùn)算的區(qū)別:

總結(jié) 

到此這篇關(guān)于C++日期類的實(shí)現(xiàn)日期計(jì)算器的文章就介紹到這了,更多相關(guān)C++日期類實(shí)現(xiàn)日期計(jì)算器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++聚合關(guān)系類的構(gòu)造函數(shù)的調(diào)用順序詳解

    C++聚合關(guān)系類的構(gòu)造函數(shù)的調(diào)用順序詳解

    下面小編就為大家?guī)硪黄狢++聚合關(guān)系類的構(gòu)造函數(shù)的調(diào)用順序詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考,一起跟隨小編過來看看吧
    2016-05-05
  • VC程序設(shè)計(jì)小技巧20例

    VC程序設(shè)計(jì)小技巧20例

    這篇文章主要介紹了VC程序設(shè)計(jì)小技巧20例,需要的朋友可以參考下
    2014-07-07
  • Opencv實(shí)現(xiàn)讀取攝像頭和視頻數(shù)據(jù)

    Opencv實(shí)現(xiàn)讀取攝像頭和視頻數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了Opencv實(shí)現(xiàn)讀取攝像頭和視頻數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • VC外部符號(hào)錯(cuò)誤_main,_WinMain@16,__beginthreadex解決方法

    VC外部符號(hào)錯(cuò)誤_main,_WinMain@16,__beginthreadex解決方法

    這篇文章主要介紹了VC外部符號(hào)錯(cuò)誤_main,_WinMain@16,__beginthreadex解決方法,實(shí)例分析了比較典型的錯(cuò)誤及對(duì)應(yīng)的解決方法,需要的朋友可以參考下
    2015-05-05
  • C++ 封裝 DLL 供 C# 調(diào)用詳細(xì)介紹

    C++ 封裝 DLL 供 C# 調(diào)用詳細(xì)介紹

    這篇文章主要介紹了C++ 封裝 DLL 供 C# 調(diào)用(以C# 調(diào)用C++ 二次封裝的VLC播放庫(kù)為介質(zhì),支持回調(diào)函數(shù)的封裝),需要的朋友可以參考下面我文章的具體內(nèi)容
    2021-09-09
  • C++超詳細(xì)分析type_traits

    C++超詳細(xì)分析type_traits

    C++的type_traits是一套純粹編譯期的邏輯,可以進(jìn)行一些類型判斷、分支選擇等,主要用于模板編程。使用type_traits并不難,但是我們希望能夠更加深入了解其實(shí)現(xiàn)方式,與此同時(shí),可以更進(jìn)一步體驗(yàn)C++的模板編程
    2022-08-08
  • C++初階教程之類和對(duì)象

    C++初階教程之類和對(duì)象

    C++是面向?qū)ο缶幊痰?這也是C++與C語(yǔ)言的最大區(qū)別,而類和對(duì)象就是C++面向?qū)ο蟮幕A(chǔ),下面這篇文章主要給大家介紹了關(guān)于C++初階教程之類和對(duì)象的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式)

    C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C/C++中的內(nèi)存管理小結(jié)

    C/C++中的內(nèi)存管理小結(jié)

    這篇文章主要介紹了C/C++中的內(nèi)存管理小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Visual Studio Code (VSCode) 配置搭建 C/C++ 開發(fā)編譯環(huán)境的流程

    Visual Studio Code (VSCode) 配置搭建 C/C++ 開發(fā)編譯環(huán)境的流程

    記得N年前剛開始接觸編程時(shí),使用的是Visual C++6.0,下面這個(gè)可愛的圖標(biāo)很多人一定很熟悉。不過今天想嘗鮮新的工具 Visual Studio Code 來搭建C/C++開發(fā)環(huán)境,感興趣的朋友一起看看吧
    2021-09-09

最新評(píng)論