【C++初阶】类和对象修炼下

类和对象下呐主要是给大家讲一下日期类的实现,至于为什么不实现一个栈呐,那是因为目前学到的拷贝构造和赋值重载都是属于一种浅拷贝,而对于栈类我们需要使用深拷贝.

一.四大默认成员函数

这里就不过多赘述了

class Date
{
public:
	//全缺省的构造函数
	Date(int year = 2022, int month = 10, int day = 13)
	{
		_year = year;
		_month = month;
		_day = day;
		if (!(_year > 0
			&& _month >= 1 && _month <= 12
			&& _day >= 1 && _day <= GetMonthDay(_year, _month)))
		{
			cout << "输入的日期不合法" << endl;
			Print();
		}
	}
	//拷贝构造(其实对于日期类可以不用写拷贝构造)
	Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//赋值重载(其实对于日期类可以不用写拷贝构造)
	Date& operator=(const Date& d2)
	{
		    _year = d2._year;
			_month = d2._month;
		    _day = d2._day;
		 return *this;
	}
	//析构函数:(其实对于日期类可以不用写析构函数)
	~Date()
	{
		_year = _month = _day = 0;
	}
	//打印日期
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	// 内置类型
	int _year;
	int _month;
	int _day;
};

注意:下面所写的函数都是日期类中的成员函数,这就意味着第一个参数都是隐含的this指针.

二.获取某年某月的天数

年分为闰年和平年,月也分为1-12月,所以对于任意一年的12个月中每一个月的天数都是基本一样的,维度在2月因为平年还是闰年相差一天.所以如果你要获取某年某月的天数,就只需对于在2月,且是闰年特殊+1天就可以.

	//获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int day = monthDay[month];
		if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0 && month == 2)
		{
			++day;
		}
		return day;
	}

这里值得一提的是,这里有两个可以优化的地方:

  1. 这里的GetMonthDay()函数会被反复调用,且monthDay数组始终不变,所以建议定义成static静态的
  2. 这里的if判断条件中,除法和取余的运算符效率低,所以建议把month==2的条件写在最前面

也就是这样:

	//获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		int _month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int _day = _month[month];
		if (month == 2 && year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
		{
			++_day;
		}
		return _day;
	}

三.日期+=天数和日期+天数

这里可以通过举例内置类型中+=和+运算符的使用特点

比如: c=a+=b和c=a+b这个例子

+=和+有一定的相似点:

返回值和参数在类型和个数上都是一样的

返回值:Date&

参数1:隐含的this指针

参数2:要+的天数

但是,+=和+也有不同点:

c=a+=b这里a的值在运算前后发生改变,

c=a+b这里a的值在运算前后没有改变.

这里日期1+=天数和日期1+天数两个函数的区别在于:

  • 日期1+=天数中,日期1在运算前后发生改变,
  • 日期1+天数中,日期1在运算前后没有改变.

这里先给大家实现operator+=(int day)函数:

image-20221013235137481

ps:值得注意的是12到1月的转变的时候,年份也要变

	Date& operator+=(int day)
	{
		if (day < 0)
		{
			return *this -= -day;
		}
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			++_month;
			if (_month == 13)
			{
				_month = 1;
				++_year;
			}
		}
		return *this;
	}

然后我们来实现一下,operator+(int day)函数:

这里我们可以调用拷贝构造一个替身,让替身的this发生改变,然后返回替身,那么就可以得到返回值的同时,本体的this却没有发生改变.

	//日期+天数
	Date operator+(int day)
	{
		Date ret(*this);
		if (day < 0)
		{
			ret -= -day;
			return ret;
		}
		ret += day;
		return ret;
	}

四.日期-=天数和日期-天数

这里和三的区别和相同点一样,这里不过多赘述.

这里是日期-天数,那么同样的先全部减在天数上,然后借位,值得注意的是12到1月的转变的时候,年份也要变

image-20221014001030087

日期-=天数:

	//日期-=天数
	Date& operator-=(int day)
	{
		if (day < 0)
		{
			*this += -day;
		}
		_day -= day;
		while (_day <= 0)
		{
			--_month;
			if (_month == 0)
			{
				_month = 12;
				--_year;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}

日期-天数:

	//日期-天数
	Date operator-(int day)
	{
		Date ret(*this);
		if (day < 0)
		{
			ret += -day;
			return ret;
		}
		ret -= day;
		return ret;
	}

ps:这里传入的天数一般都是正数,如果天数是负数的话,日原来的日期-天数就想当与日期+(-天数),同样可以代码复用.

五.日期比较

这里代码书写起来比较简单,这里只想给大家讲一下复用的问题:写了>和==其他日期比较,比如>=或者<或者!=都可以通过函数复用实现.

	//==运算符
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	
	//<运算符重载
	bool operator<(const Date& d)
	{
		return !(*this > d || *this == d);
	}

复用>和==的代码,可以完成:

	//>=运算符
	bool operator>=(const Date& d)
	{
		return *this > d || *this == d;
	}

	//<=运算符
	bool operator<=(const Date& d)
	{
		return !(*this > d);
	}
	//!=运算符
	bool operator!=(const Date& d)
	{
		return !(*this == d);
	}

六.日期++和++日期

首先,日期++和++日期也就是我们常说的b=a++和b=++a的区别:

但是这里会出现一个比较尴尬的问题:

这里的要写的两个运算符重载函数都使用的是一个运算符++,所以在书写成员函数的时候函数名肯定都是

operator++,那么当我们写同时使用了d2=d1++和d2=++d1的时候,我们就写一个函数肯定不行,所以C++语法就规定:

前置++和后置++的运算符重载函数使用operator++作为函数名,但是前置++的运算符重载函数不带参数,后置++的运算符重载函数带一个int类型作以区分.

	//前置++: 比如y=++x;
	Date& operator++()
	{
		*this += 1;
		return *this;
	}
	
	//后置++: 比如y=x++;
	Date operator++(int)
	{
	    //记录最初值
		Date ret(*this);
		*this += 1;
        //返回最初值
		return ret;
	}

值得注意的是,后置++中只能传值返回,因为出了作用域ret就不存在了,不能传引用返回.

所以后置++这里要调用两次拷贝构造,一般推荐使用前置++

七.日期-日期

日期+日期就和指针+指针一样,没有任何意义,所以这里不讨论日期+日期

另外运算的结果是两个日期相差的天数,所以没法日期-=日期

所以我们只讨论日期-日期:

方法1:从日期1遍历到日期2计数,直至相等,推荐

	//日期-日期: 
	int operator-(const Date& d)
	{
		Date max = *this;
		Date min = d;
		int flag = 1;
		if (*this < d)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int count = 0;
		while (min != max)
		{
			++min;
			++count;
		}
		return flag * count;
	}

方法2:选定一个起始位置0-1-1,分别计算日期1和日期2到起始位置的天数,然后两个天数相减

注意:这里要先求从0到_year-1这几年的整年天数,再算当前年从1- _month-1这几月的天数,最后再加上 _day

	//日期-日期: 
	int GetDay(const Date& d)
	{
		int day = 0;
		for (int i = 0; i < d._year; i++)
		{
			day += 365;
			if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)
			{
				++day;
			}
		}
		for (int i = 1; i < d._month; i++)
		{
			day += GetMonthDay(d._year, i);
		}
		day += d._year;
		return day;
	}

	int operator-(const Date& d)
	{
		int day1 = GetDay(*this);
		int day2 = GetDay(d);
		return day1 - day2;
	}

image-20221014010558939

image-20221014011430354

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上心头

为爱发电

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值