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

C++ 如何實現(xiàn)一個日期類

 更新時間:2024年10月23日 10:19:45   作者:FFDUST  
通過對類和對象的學習,理解了類是對象的抽象描述,實現(xiàn)日期類涉及定義年月日屬性及成員函數(shù)如打印日期、日期加減,重點介紹了運算符重載的概念和作用,通過代碼示例展示了如何實現(xiàn)一個日期類,包括頭文件和源文件的分離編寫

一. 對日期類的介紹

通過對類和對象(這里鏈接是類和對象的介紹)的學習,類就是一種模型一樣的東西,是對象一種抽象的描述。所以實現(xiàn)日期類,就是實現(xiàn)一個日期模型,里面有所對應(yīng)的成員變量(屬性:年/月/日),還有一些它的方法(成員函數(shù):打印該日期、對日期加減等)。

二. 實現(xiàn)日期類

在實現(xiàn)日期類之前,我們還需要了解一下運算符重載,這是為了后續(xù)我們對日期的加、減天數(shù)以及日期減日期等做準備,因為當運算符被用于類類型的對象時,需要我們?nèi)ブ剌d運算符去指定新的含義。(C++規(guī)定類類型對象使用運算符時,必須轉(zhuǎn)換成調(diào)用對應(yīng)運算符重載,若沒有對應(yīng)的運算符重載,則會編譯報錯。

//內(nèi)置類型
int i = 1;
int j = 2;
int sum = 0;
i = i + 1;
sum = i - j;
//自定義類型對象若想用類似上面的就需要在類里面聲明定義對應(yīng)的運算符重載函數(shù)

1. 運算符重載

C++規(guī)定類類型對象使用運算符時,必須轉(zhuǎn)換成對應(yīng)運算符重載,若沒有對應(yīng)的運算符重載,則會編譯報錯。

也就是運算符被用于類類型的對象時,可以通過運算符重載的形式指定新的含義。

運算符重載是一個函數(shù),它的名字是由關(guān)鍵字operator和運算符組成,也具有返回類型、參數(shù)列表、函數(shù)體。

class A
{
public:
    A(int a = 1, int b = 1)
        :_a(a)
        ,_b(b)
    {}
    //這里就是賦值運算符重載
    A& operator=(const A& a)
    {
        _a = a._a;
        _b = a._b;
        return *this;
    }
private:
    int _a;
    int _b;
};
int main()
{
    A a1;
    A a2(5, 2);
    a1 = a2;
    return 0;
}

我們來查看驗證是否按照指定新的含義進行:

賦值之前:

賦值之后:

 可以看到a1里的成員確實被a2里的成員變量賦值了。

注意:

//上述代碼中
 a1 = a2;
//其實詳細寫法是:
a1.operator=(a2);
//但它們倆意義相同都是為了調(diào)用賦值運算符重載//上述代碼中
 a1 = a2;
//其實詳細寫法是:
a1.operator=(a2);
//但它們倆意義相同都是為了調(diào)用賦值運算符重載

一元運算符只有一個參數(shù),二元運算符要有兩個參數(shù)。(注意:二元運算符的左側(cè)運算對象傳給第一個參數(shù),右側(cè)運算對象傳給第二個參數(shù))。

也就是說,重載運算符函數(shù)的參數(shù)個數(shù)和該運算符作用的運算對象數(shù)量一致的。

上面我們看到A類重載=運算符只寫了一個函數(shù)參數(shù),這是因為它是成員函數(shù),第一個參數(shù)默認傳了this指針(類和對象有介紹)。

注意:重載運算符必須至少有一個類類型的形參,不能通過運算符重載改變內(nèi)置類型對象的含義。

若不是成員函數(shù),就按照上面規(guī)則來:

class A
{
public:
    A(int a = 1, int b = 1)
        :_a(a)
        ,_b(b)
    {}
    A& operator=(const A& a)
    {
        _a = a._a;
        _b = a._b;
        return *this;
    }
    int _a;
    int _b;
};
//注意:operator + 必須至少有一個類類型的形參,否則會報錯,就比如下面注釋掉的情況
//int operator(int a,int n)
//{
//    return a-n;
//}
int operator+(const A& a, int& n)
{
    return a._a + n;  //這里成員變量需要放公有,否則不能直接訪問
}
int main()
{
    A a;
    int n = 10;
    cout << a + n << endl;
    return 0;
}

 運算符重載以后,優(yōu)先級和結(jié)合性與對應(yīng)的內(nèi)置類型運算符保持一致的。

不能重載的情況: 

不能用沒有的符號創(chuàng)建新的操作符(運算符)

//例如:
operator@ //就不能創(chuàng)建

有五個運算符是不能重載的:.*    ::    sizeof     ?:   . 

 后四個是經(jīng)常用到的,第一個非常用,下面單獨拿出來解釋

//函數(shù)指針較為特別,typedef類型需要這樣寫
typedef void (*PF)(); 
class A
{
public:
	void func()
	{
		cout << "A::func()" << endl;
	}
};
//若typedef成員函數(shù)指針類型,就加個指定類域即可
typedef void(A::*PF)();
// .*運算符就用于以下方式回調(diào)函數(shù)的場景(成員函數(shù)回調(diào))
int main()
{
	//成員函數(shù)要加&才能取到函數(shù)指針
	PF pf = &A::func;      //這里相當于 void(A::*pf)() = &A::func;
	A a;
	(a.*pf)();
	return 0;
}

(深入理解指針) 

//這里是普通全局函數(shù)回調(diào)的形式
(*pf)();

所以這個符號的意義是對象調(diào)用成員函數(shù)指針時,成員函數(shù)的回調(diào) (注意:考慮有隱含的this指針,不能顯示寫形參和傳實參)

重載++運算符時,前置++與后置++的運算符重載函數(shù)名都是operator++,無法來區(qū)分。 C++規(guī)定,后置++重載時,增加一個int形參,跟前置++構(gòu)成函數(shù)重載,方便區(qū)分。

class Date
{
public:
	//構(gòu)造函數(shù)
	Date(int year = 1900,int month =1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	//前置++
	Date& operator++()
	{
		cout << "這里是前置++" << endl;  //這里演示一下,先不實現(xiàn)
		return *this;
	}
	//后置++
	Date& operator++(int)  //這里的加不加形參名都可以,必須要有int (只要整型)
	{
		Date tmp;
		cout << "這里是后置++" << endl;  
		return tmp;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2;
	++d1;
	d2++;
	d2.operator++(10); //這里傳不傳值都可以,因為那個int一般不接收。 
}

注意:重載的++運算符也要與內(nèi)置類型++運算符規(guī)則一致(前置++:先++,再返回++后的結(jié)果,不產(chǎn)生拷貝;后置++:進行++,++之后返回的是++前的結(jié)果,會產(chǎn)生拷貝。所以,一般開以選擇前置++來減少拷貝)。

我們實現(xiàn)日期類,還想需要可以對這個日期cout和cin來方便輸出和輸入,所以<<和>>也是可以重載的,但是需要重載成全局函數(shù),重載為全局函數(shù)把ostream/istream放到第一個形參位置就可以了,第二個形參位置當類類型對象。否則會有隱含的this指針,導致調(diào)用時變成:對象<<cout ,不符合使用習慣和可讀性(想要的是:cout<<對象)。

2.日期類實現(xiàn)代碼

我們可以聲明定義分離來實現(xiàn),分別創(chuàng)建Date.h頭文件和Date.cpp用來定義頭文件聲明的函數(shù)。

//Date.h
#include<iostream>
#include <assert.h>
using namespace std;
class Date
{
	//友元函數(shù)聲明 --這兩個全局函數(shù)就可以訪問對象的私有成員
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	//構(gòu)造函數(shù),若沒有傳參 就是默認構(gòu)造 全缺省函數(shù)
	Date(int year = 1900, int month = 1, int day = 1);
	//拷貝構(gòu)造
	Date(const Date& d);
	void Print()const;  //打印日期
	bool CheckDate() const;  //檢查日期輸入是否正確
	//頻繁調(diào)用的建議直接定義類里面,默認inline內(nèi)聯(lián)
	int GetMonthDay(int year, int month)const  
	{
		assert(month > 0 && month < 13);
		static int monthDay[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 }; //因為沒有0月,將0置-1空出來
		//用static修飾是因為這個數(shù)組會頻繁調(diào)用,直接放在靜態(tài)區(qū)
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			return 29;
		}
		return monthDay[month];
	}
	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 = d2
	Date& operator=(const Date& d);
	Date operator+(int day) const;
	Date& operator+=(int day);
	Date operator-(int day) const;
	Date& operator-=(int day);
	// d1++;
	// d1.operator++(0);
	Date operator++(int);
	// ++d1;
	// d1.operator++();
	Date& operator++();
	// d1--;
	// d1.operator--(0);
	Date operator--(int);
	// --d1;
	// d1.operator--();
	Date& operator--();
	// d1 - d2
	int operator-(const Date& d) const;
	//void operator<<(ostream& out);
	Date* operator&() //取地址運算符重載 
                       //普通對象返回類型Date*
	{
		return (Date*)0x2673FF40;  //返回假地址
	}
	const Date* operator&() const  //取地址運算符重載 
                            //const對象要調(diào)用const成員函數(shù)要返回類型const Date*
	{
		return (Date*)0x2673FE30; //返回假地址	
	}
private:
	int _year;
	int _month;
	int _day;
};
//重載流插入流提取
// ostream/istream類型對象不能傳值只能傳引用,否則會報錯,因為c++不支持它們的拷貝構(gòu)造。
//要寫成全局函數(shù) 否則調(diào)用的時候需要這樣寫:d1<<cout    d1>>cin   用著會比較別扭
//因為如果寫成了成員函數(shù)第一個參數(shù)有隱藏的this指針,并且不能修改
//cout是ostream類型的 (也可以用void返回類型但不建議)
//cin默認關(guān)聯(lián)cout
//在cin進行i/o操作前會刷新cout的緩沖區(qū)
//流插入
ostream& operator<<(ostream& out, const Date& d);
//流提取
//這里第一個參數(shù)不能加const修飾了,因為提取的值要放日期類對象里
istream& operator>>(istream& in, Date& d);
//Date.cpp
#include "Date.h"
bool Date::CheckDate() const//檢查日期正確
{
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	else
	{
		return true;
	}
}
Date::Date(int year, int month, int day)  //構(gòu)造函數(shù)(全缺省,前面聲明中已經(jīng)給了缺省值,定義這里就不能再寫出來了)
{
	_year = year;
	_month = month;
	_day = day;
	if (!CheckDate())
	{
		cout << "非法日期:";
		Print();
	}
	cout << endl;
}
Date::Date(const Date& d)   //拷貝構(gòu)造
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
void Date::Print()const  //打印日期
{
	cout << _year << "/" << _month << "/" << _day << endl;
}
//d1 = d2
Date& Date::operator=(const Date& d)
{
	if (*this != d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}
Date& Date::operator+=(int day)  //加等可以讓自己改變    
{
	//先判斷day是否是負數(shù) ---- _day+(-day)==_day-day
	if (day < 0)
	{
		return *this -= (-day);
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}
Date Date::operator+(int day) const //只加不能改變自己  
//這里不能用傳引用返回 因為這里用const修飾只讀取不想改變自己,引用會把權(quán)限放大
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}
//- -=同+ +=
Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}
Date& Date::operator-=(int day)
{
	//先判斷day是否是負數(shù)  --->_day-(-day)==_day+day
	if (day < 0)         
	{
		return *this += (-day);
	}
	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
//d1<d2
bool Date::operator<(const Date& d) const  //這里傳引用 d就是d2的別名 也就是d2的本身
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
		{
			return true;
		}
		if (_month == d._month)
		{
			return _day < d._day;
		}
	}
	return false;
}
//d1<=d2
//這里就可以復(fù)用函數(shù)了
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);
}
// d1++;  后置++有拷貝
// d1.operator++(0);
//用的時候括號里只要是整數(shù)都可以
Date Date::operator++(int)  // 加不加形參名都可以,一般不接收
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}
// ++d1;  //前置++無拷貝
// d1.operator++();
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
//-- 同理++
// d1--;
// d1.operator--(0);
Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}
// --d1;
// d1.operator--();
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
// d1 - d2
int Date::operator-(const Date& d) const
{
	Date max = *this;  //假設(shè)第一個大
	Date min = d;   //第二個小
	int flag = 1;   //等于1時表示第一個大第二個小
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;       //第二個大第一個小
	}
	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}
	return n *= flag;
}
//流插入cout<<d1<<d2
ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
//流提取cin>>d1>d2
istream& operator>>(istream& in, Date& d)
{
	cout << "請依次輸入年月日:>";
	in >> d._year >> d._month >> d._day;
	//檢查日期是否非法
	if (!d.CheckDate())
	{
		cout << "非法日期: " << d << "請重新輸入" << endl;
		while (1)
		{
			cout << "請依次輸入年月日:>";
			in >> d._year >> d._month >> d._day;
			if (!d.CheckDate())
			{
				cout << "輸入日期非法:";
				d.Print();
				cout << "請重新輸入!!!" << endl;
			}
			else
			{
				break;
			}
		}
	}
	return in;
}

 有些注意事項,在上面代碼的實現(xiàn)注釋中有一些解釋。

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

相關(guān)文章

  • C++項目實戰(zhàn)之makefile使用

    C++項目實戰(zhàn)之makefile使用

    這篇文章主要介紹了C++項目實戰(zhàn)之makefile使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • C++/JAVA/C#子類調(diào)用父類函數(shù)情況總結(jié)

    C++/JAVA/C#子類調(diào)用父類函數(shù)情況總結(jié)

    今天小編就為大家分享一篇關(guān)于C++/JAVA/C#子類調(diào)用父類函數(shù)情況總結(jié),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Visual Studio中scanf函數(shù)報錯的幾種解決方法

    Visual Studio中scanf函數(shù)報錯的幾種解決方法

    本文主要介紹了Visual Studio中scanf函數(shù)報錯的幾種解決方法,文中通過圖文示例介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-03-03
  • C++標準模板庫vector的常用操作

    C++標準模板庫vector的常用操作

    今天小編就為大家分享一篇關(guān)于C++標準模板庫vector的常用操作,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • STL常用容器詳細解析

    STL常用容器詳細解析

    這里我們不涉及容器的基本操作之類,只是要討論一下各個容器其各自的特點STL中的常用容器包括:順序性容器(vector、deque、list)、關(guān)聯(lián)容器(map、set)、容器適配器(queue、stac)
    2013-09-09
  • Qt自定義表頭實現(xiàn)過濾功能的方法

    Qt自定義表頭實現(xiàn)過濾功能的方法

    這篇文章主要個給大家介紹了關(guān)于Qt自定義表頭實現(xiàn)過濾功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Qt具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-07-07
  • 關(guān)于C++中定義比較函數(shù)的三種方法小結(jié)

    關(guān)于C++中定義比較函數(shù)的三種方法小結(jié)

    下面小編就為大家?guī)硪黄P(guān)于C++中定義比較函數(shù)的三種方法小結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • C++中的類型轉(zhuǎn)換static_cast、dynamic_cast、const_cast和reinterpret_cast總結(jié)

    C++中的類型轉(zhuǎn)換static_cast、dynamic_cast、const_cast和reinterpret_cas

    這篇文章主要介紹了C++中的類型轉(zhuǎn)換static_cast、dynamic_cast、const_cast和reinterpret_cast總結(jié),需要的朋友可以參考下
    2014-10-10
  • C++實現(xiàn)LeetCode(169.求大多數(shù))

    C++實現(xiàn)LeetCode(169.求大多數(shù))

    這篇文章主要介紹了C++實現(xiàn)LeetCode(169.求大多數(shù)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 全面了解C語言?static?關(guān)鍵字

    全面了解C語言?static?關(guān)鍵字

    這篇文章主要介紹了全面了解C語言?static?關(guān)鍵字,文章首先通過先介紹一下頭文件的創(chuàng)建展開主題的詳細內(nèi)容,需要的小伙伴可以參考一下
    2022-04-04

最新評論