C++ ~ 日期计算器例子讲解类和对象下

目录

 1.介绍

2.计算往后day天 

2.1逻辑分析

2.2代码优化

3.计算往前day天

3.1代码分析

3.2遇到的问题

3.3补充逻辑

 4.补充++运算符重载

5.'<<'  流插入和  '>>'  流提取


 1.介绍

我将通过不断添加函数的方法讲解如何实现,和改进前面的函数,也对之前讲的进行补充和改进,更好的理解类和对象,尽量用最少的字来描述清楚

class Date
{
public:
    //默认构造
	Date(int year = 2024, int month = 1, int day = 29)
	{
		assert(month > 0 && month < 13 && day <= GetMonthDay(year, month));
		_year = year;
		_month = month;
		_day = day;
		
	}
    //拷贝构造
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
    //赋值运算符重载
	Date& operator=(const Date& d)//赋值运算符重载
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
    //析构函数
	~Date()
	{
		_year = 0;
		_month = 0;
		_day = 0;
	}


private://声明   main里Date d1; 是定义(对象整体的定义)
	int _year;
	int _month;
	int _day;
};

对于这Date类(没有堆空间开辟),这里的四个都可以不写(编译器会自己生成),默认构造里的assert可以忽略

注意:赋值和取地址运算符是唯一可以直接调用的,因为它们是默认成员函数,像比较运算符,+,+=,++这些要自己写(下文解释)

2.计算往后day天 

class Date
{
public:
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		int array[13] = { 0,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 array[month];
	}
	Date& operator+=(int day)//date += 100;
	{
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	Date operator+(int day) const
	{
		Date tmp = *this;//拷贝构造
		tmp += day;
		return tmp;//传值返回,拷贝构造
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 1, 30);
	d1 += 1000;

	return 0;
}

还没有写  '<<' 流插入运算符重载,就到监视窗口看

和日期计算器里的一样

2.1逻辑分析

1.GetMonthDay这个函数,唯一区别是一个闰年的29天,那么可以把其他月天数放在数组里

2.+=是要改变*this的所以直接操作成员变量,考虑到赋值运算符的连续性,return *this,出了函数*this还存在,那么传引用返回

3.+的话,是不改变自己,那么就实例化一个对象出来,会调用两次拷贝构造,但是我在调试的时候发现,传值返回没有走到拷贝构造里,查阅资料发现 简单来说这是编译器的优化,但是在逻辑上仍然要返回一个Date类型的临时对象

2.2代码优化

1.我已经是优化好了的(逻辑还差一点,day是负的),用+=去复用+可以减少拷贝构造

2.发现我在operator+这个函数后面加了const,这个是对*this的修饰,

补全这样:const Date* this

就是不能修改*this了,我第一次讲的不到位(直接理解const),其实我们不需要自己增加任何规则:

说白了无非是两种①const  Date*  this  ② Date*  const  this;

那么看:*this就是对象,放在C里说就是变量,那么const修饰了这个变量,变量不能变;

                this是指针,const修饰了指针,指针不能变

3.计算往前day天

class Date
{
public:
	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		int array[13] = { 0,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 array[month];
	}
	Date& operator-=(int day)
	{
		_day -= day;
		while (_day <= 0)//<=0去上个月借
		{
			//法一先改_day
			//if(_month > 1)
			//	_day += GetMonthDay(_year, _month - 1);
			//if (_month == 1)//单独拿出来,一月去借12月的
			//	_day += 31;
			//_month--;
			//if (_month == 0)
			//{
			//	_year--;
			//	_month = 12;
			//}

			//法二先改_month
			_month--;
			if (_month == 0)
			{
				_month = 12;
				_year--;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}
	Date operator-(int day)//运损符重载又可以构成函数重载
	{
		Date tmp = *this;
		tmp -= day;
		return tmp;
	}
	int operator-(const Date& d)const
	{
        //法一
		/*int n = 0;
		Date left = *this;
		Date right = d;
		if (left > right)
		{
			while (left > right)
				right++, n++;
			return n;
		}
		else
		{
			while (left < right)
				left++, n++;
			return -n;
		}*/
        //法二
		Date max = *this;
		Date min = d;
		int flag = 1;
		//☆☆☆if (*this < d)///因为上面的<   最操作数没加const☆☆☆①
		if(max < min)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int n = 0;
		while (min < max)
		{
			++min;
			++n;
		}
		return n * flag;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 1, 30);
	d1 -= 1000;

	return 0;
}

 运行结果没问题

3.1代码分析

这里有个 ‘-’ 减号运算符重载

①日期 =  日期  -  天数

②天数 =  日期  -  日期

3.2遇到的问题

①这句代码:if(max < min),我第一次是这么写的:if(*this < d),出现没有与这些操作数匹配的 "<" 运算符,我前面不是写了吗?问题出在这:我的函数声明,int operator-(const Date& d)const

后面要写const,为什么后面写??主要是为了防止两个const对象没法调用

也就是*this是const,但是我写的 :bool operator<(const Date& d)这个声明是左参数不是const,所以发生权限的放大,也就是类型的不匹配

改进比较运算符函数重载就是在声明后面加上const,避免找不到对应的函数重载

3.3补充逻辑

	Date& operator+=(int day)//date += 100;
	{
		if (day < 0)
		{
			*this -= -day;
			return *this;
		}
        //...
	}
    Date& operator-=(int day)
	{

		if (day < 0)
		{
			*this += -day;
			return *this;
		}
        //...    
    }

往前走负的,就是往后多少天;往后走负的,就是往前多少天

有没有人会有这样的问题:比如1.30前面的30天就是1.10号吗?是9?10?11?

①昨天就是当天-1!

②这样清楚吧 ,1.29的前5天

C++ ~ 日期计算器例子讲解类和对象下_第1张图片

结论:所以直接减就行了

 4.补充++运算符重载

	//前置++
    Date& operator++()
	{
		*this += 1;
		return *this;
	}
    //后置++
	Date operator++(int)//站位,与前置++构成运算符重载
	{
		Date tmp = *this;//拷贝构造
		*this += 1;
		return tmp;//拷贝构造//调试的时候没有
	}

后置++里面的int 启到站位作用,没有实际意义,为了构成重载,可以不写形参

这里的传引用返回和传值返回应该是没问题了吧

5.'<<'  流插入和  '>>'  流提取

如果我们写在Date类里面

void operator<<(ostream& out)//传进来的参数是cout//日期类对象*this抢占了第一个参数
{

}

那我们调用的时候就要这么写:d1<

没有,因为第一个参数一定是*this,在调用的时候是这样的d1<d1.operator<<(cout)

所以只能写在全局

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << '/' << d._month << '/' << d._day;
	return out;
}

istream& operator>>(istream& in, Date& d) 
{
	in >> d._year >> d._month >> d._day;
	return in;
}

但是还是不对_year,_month,_day是私有成员变量,类外无法访问

法一:函数里增加GetYear()这类函数

法二:友元函数,在类里加上friend ostream& operator<<(ostream& out, const Date& d);即可,格式为 friend+函数声明 + ;

:out就是传进来的cout对象

问题①:把out,都改成cout会调用std库里的cout吗?

                不会,因为局部优先,这只是个形参,但是这个形参就是std::cout

问题②:为什么ostream&这么传返回值,其实返回的就是std::cout,为了连续输出

//显示调用
operator<<(cout, d1);
//隐式调用
cout << d1;

这部分细节比较多,还是要查阅资料,一下讲完和标题不匹配了,[]运算符,内联,初始列表,static,内部类下一部分举例子,放平心一定能学会的,我也花了很长时间,也是初学者,讲的不一定对,带着怀疑看吧!

你可能感兴趣的:(c++,算法,c语言)