类与对象---砥柱代码练习篇(c++)

0. 前言

构造函数、析构函数、拷贝构造、赋值重载、取地址重载-普通对象和const对象取地址。

像下面这两种就是取地址重载,一般我们使用默认的就可以了,除非你不想让别人找到你的地址这种情况就可以用了。

class Date
{
public :
	Date* operator&()
	{
		return this ;
	}

	const Date* operator&() const
	{
		return this ;
	}
private :
	int _year ; // 年
	int _month ; // 月
	int _day ; // 日
};

谈到这里可能,部分友友不知到这段代码什么意思?

const Date* operator&() const

类的成员函数还有一个隐形的this指针,而后面const,就是修饰*this也就是this指向的内容。

//const Date* operator&(const Date* const this) 
这只是方便理解,实践中在类内部不要这样写。

稍微转换一下,变成可读的代码就是这样了。

划到此处,我们谈谈本章对日期类的应用。

00. 链接

链接:类与对象—类的默认成员函数

01. 日期类的实现–声明

这个标题内容,写的是日期的大概方向;感兴趣的友友们可以多写几个,例如:日期转换星期,或者写个菜单来感受一番小程序的乐趣。

写之前注意声明和定义分离,小丁现阶段用的是vs2019
在这里插入图片描述

声明–内联函数就直接放在声明里。

#pragma once
#include<assert.h>
#include<iostream>
using std::cout;
using std::endl;
using std::cin;   //展开部分。
using std::ostream;
using std::istream;

//#include<iostream>
//using namespace std;  全部展开。

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		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 % 400 == 0) ||
			(year % 4 == 0 && year % 100 != 0)))
		{
			day += 1;
		}

		return day;
	}

	//检查输入日期是否合理性。
	bool CheckDate();

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
		
		assert(!CheckDate());
	}

	// 拷贝构造函数
  // d2(d1)
	Date(const Date& d);

	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);

	// 析构函数
	~Date();

	// 日期+=天数
	Date& operator+=(int day);

	// 日期+天数
	Date operator+(int day) const;

	// 日期-天数
	Date operator-(int day) const;

	// 日期-=天数
	Date& operator-=(int day);

	// 前置++
	Date& operator++();

	// 后置++
	Date operator++(int);

	// 后置--
	Date operator--(int);

	// 前置--
	Date& operator--();

	// >运算符重载
	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;

	// 日期-日期 返回天数
	int operator-(const Date& d) const;

	//打印日期
	void Print() const
	{
		cout << _year << '/' << _month << '/' << _day << endl;
	}

	//友元,可以让它访问私有成员变量。
	//流插入和流提取没有直接打印或输入的日期,这需要我们来写一个运算符重载。
	friend ostream& operator<<(ostream& out, const Date& d); //流插入
	friend istream& operator>>(istream& in, Date& d); //流提取
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;
}
#include<iostream>
using std::cout;
using std::endl;
using std::cin;   //展开部分。
using std::ostream;
using std::istream;

//#include<iostream>
//using namespace std;  全部展开。

顺便提一下,部分展开比全部展开更安全;只展开常使用的,这是一个较好的习惯。

友元,可以让它访问私有成员变量。

friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);

前面全局函数前面加个friend这个关键字,外面函数就可以访问私有成员变量了。
注意:

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

这个时候,友友们就会像我直接放在类实现来实现流插入和流提取,确实可以。

istream& operator>>(istream& in,)
ostream& operator<<(ostream& out)

确实可以,可是只能 d1>>d2>>cin d1<<d2<<cout这样调用, 不仅别扭还可能误导人。

02. 日期类的实现–构造函数

构造函数分两种

//	1.无参构造函数
Date()
{}
//	2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}

我们可以写个缺省函数来玩

// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
		//检查日期是否合法。
		assert(!CheckDate());
	}

03. 日期类的实现–拷贝构造函数

拷贝构造函数就是构造函数的一个重载形式,只有一个参数类型;我们使用类类型的引用。

// 拷贝构造函数
  // d2(d1)
Date::Date(const Date& d)  //Date:: 就像一个指示牌,来在类里查找。
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

没什么可说的。

04. 日期类实现–赋值运算符重载

赋值运算符重载注意不要与拷贝构造函数弄混。
例子:

1.Date d1;
1.Date d2(d1);或者这样写Date d2=d1;

2.Date d1;
2.Date d2(2022, 7, 26);
2.d1=d2;

明显看出1.是拷贝构造函数,2.是赋值运算符重载。

// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	if (this != &d) //防止出现d1=d1,这种自己给自己的。
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	return *this;
}

注意:引用的使用和范围。

05. 日期类实现–日期与天数的加减

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day; //防止传参传个负数。
	}
	
	//先累加,符合条件再逐天减,逐月、年的加。
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month > 12) //十三月份就是,下一年的一月份。
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}

// 日期+天数
Date Date::operator+(int day) const
{
	Date ret = *this;
	ret += day;

	return ret;
}

// 日期-天数
Date Date::operator-(int day) const
{
	Date ret = *this;
	ret -= day;

	return ret;
}

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)//防止传参传个负数。
	{
		return *this += -day;
	}

	_day -= day;
	while (_day <= 0)
	{
		_day += GetMonthDay(_year, _month);
		--_month;
		if (_month == 0)
		{
			--_year;
			_month = 12;
		}
	}

	return *this;
}

-=或+=都需要返回值,我们使用引用;而且还可以实现-或+的时候复用一下。

// 前置++
Date& operator++();

// 后置++
Date operator++(int);

// 后置--
Date operator--(int);

// 前置--
Date& operator--();

明显看出前置与后置的区别是又没有int,int只是用来区分,想传参也可以传。

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

// 后置++
Date Date::operator++(int)
{
	Date ret = *this;
	*this += 1;
	return ret;
}

// 后置--
Date Date::operator--(int)
{
	Date ret = *this;
	*this -= 1;
	return ret;
}

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

06. 日期类实现–运算符重载

// >运算符重载
bool Date::operator>(const Date& d) const
{
	if ((_year > d._year) ||
		(_year > d._year && _month > d._month) ||
		(_year > d._year && _month > d._month && _day > d._day))
	{
		return true;
	}
	
	return false;
}

// ==运算符重载
bool Date::operator==(const Date& d) const
{
	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);
}

注意:复用。

06. 日期类实现–日期减日期并返回天数

// 日期-日期 返回天数。
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 flag * n;
}

注意:复用。

00// 展示:

最后还有一个判断函数参上:

//检查日期是否合理
bool Date::CheckDate()
{
	if ((_month > 0 && _month <= 12) ||
		(_day > 0 && _day <= GetMonthDay(_year, _month)))
	{
		return true;
	}

	return false;
}

测试用例自己随便写一些,我的测试用例测试后如图:
在这里插入图片描述
.
.
.
感觉有所收获的话,友友们给小丁一个赞?。


版权声明:本文为Dingyuan0原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。