前言:
现时兄弟们对“c语言__date__”大致比较着重,小伙伴们都需要了解一些“c语言__date__”的相关知识。那么小编也在网上汇集了一些对于“c语言__date__””的相关资讯,希望同学们能喜欢,同学们一起来了解一下吧!一:前言
C++类和对象里面的默认成员函数,如构造函数,拷贝构造赋值重载这些问题虽然说是不难,但是想要写出一个标准的类还是具有一定挑战性的。而编写日期类是一个很好的练手项目
主要可以分为两类,一类就是构造函数,析构函数,拷贝构造等,一类运算符的重载等问题。
二:准备(1)实现文件
主要分为三个文件
Date.h中存放的是关于类的声明Date.cpp中存放的是关于函数的实现Test.cpp中用于逻辑控制(2)基本布局
Date.h中的类及需要实现的函数声明如下,其中有些声明为什么要这样写,将在本文后面具体讲述
对应位置可跳转
序号
题目
跳转
注意事项
1-1
构造函数
点击跳转
1.函数声明和实现不要一样 2.实现获取天数函数
1-2
拷贝构造
点击跳转
注意this指针
1-3
析构函数
点击跳转
浅拷贝与深拷贝
2-0
赋值运算符重载
点击跳转
this指针
2-1
日期+=天数
点击跳转
实现逻辑问题
2-2
日期+天数
点击跳转
注意复用,和+=的区别
2-3
日期-=天数
点击跳转
实现逻辑问题
2-4
日期-天数
点击跳转
注意复用,和-=的区别
2-5
前置++和后置++
点击跳转
前置++和后置++的区别
2-6
前置–和后置–
点击跳转
前置–和后置–的区别
3-1
==重载
点击跳转
注意复用
3-2
>重载和其它重载
点击跳转
注意复用
4-1
日期相减
点击跳转
实现逻辑
三:具体实现(1)默认成员函数实现
关于C++默认成员函数,都在下文中详细叙述过了,请移步
默认成员函数
A:全缺省构造函数
前言
全缺省构造函数如果没有传入实参将会用默认设置地形参,如果实际传入了实参,形参将会使用使用实参。对于日期类有点特殊,有如下限制
年份可以无限大,但是不能小于0月份最小是1,最大是12每月的天数有28,29,30,31这四种选择,但本质最特殊还是二月,闰年29天,平年28天
进行条件限制时,1,2两条可以很好的实现,可以写成if(year>0 && month>0 && month <13 && day>0)<但是对于第三条就麻烦了。
所以我们必须实现一个获得当月天数的函数,其实不止是这个构造函数要用,后面的很多函数都要用,所以也可以将其设置为内联函数
关于这个函数实现逻辑有很多,这里推荐一个比较优秀的方法:
定义一个数组,内含13条数据,下标为0的那个数据定义为0,剩余的下标对应的数据依次设置为下标所对应的月份的天数,其中下标为2的先默认设置为28。比如下标为3代表3月,那么对应数据为31。然后利用外部传入的月份,挑出对应元素,接着判断如果是2月同时是闰年,那么天数+1。
缺省构造函数实现
有了上述函数,根据构造函数定义及注意事项可实现如下
Date::Date(int year, int month, int day){ if (year >= 0 && month > 0 && month < 13 && day>0 && day < GetMonthDay(year, month)) { _year=year; _month=month; _day=day; } else std::cout << "数据错误" << std::endl;}B:拷贝构造
拷贝构造函数是构造函数的重载形式。所以很简单,注意this指针
Date d2(d1)相当于Date d2=d1
Date::Date(const Date& d){ _year = d._year; _month = d._month; _day = d._day;}C:析构函数
前文说过,对于日期类其实现的是浅拷贝,而对于某些带有的指针应该是深拷贝,所以对于日期类即便析构函数不写也是没有问题的
(2)赋值运算符重载
关于C++赋值运算符重载,都在下文中详细叙述过了,请移步
默认成员函数
需要明白的一点是赋值赋值运算符重载究竟用来干嘛?对于内置类型,我们做以下操作,编译器是肯定知道的
int main(){ int i=1; int j=2; i+=1; j=i+1; i-=1; j=i-1; i++; ++i i--; --i; }
但是对于自定义类型,比如今天要实现的日期类,如果进行如上的运算符操作,编译器是不可能知道的,这其中的逻辑就要我们自己实现,让这些赋值运算符能够对咋们的自定义类型操作,以达到“看见这个表达式就知道什么意思”的用途
这其中,不管是哪种元素符,都一个非常基础的运算符,那就是赋值号,它的重载如下
Date& Date::operator=(const Date& d){ if (this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this;}A:日期+=天数
如果是2021-2-23+=2,那么其结果为2021-2-25
注意返回值为什么是return *this
如果是2021-2-23+=10,那么其结果为2021-2-33,但是这样的结果肯定是不合理的。所以一旦出现不合理,用加之后的结果减去当月的合理天数,比如这里就是33-28=5,然后月份+1,则其结果为2021-3-5
如果是2021-2-23+=60,那么其结果为2021-2-83,那么按照之前步骤,先执行一次为2021-3-55,仍然不合理继续计算为2021-4-24,
如果是2021-12-30+=20,那么这显然要跨年了,注意月份就要归为1,年份向前走,其结果为2022-1-9
Date& Date::operator+=(int day){ _day = _day + day; while(_day > GetMonthDay(_year, _month)) { _day=_day-GetMonthDay(_year,_month); _month ++; if(_month==13) { _month = 1; _year++; } } return *this;}B:日期+天数
关于+=和+很多人都分不清楚
int main(){ int i=0; int j=0; i+=1;//i变了 i+1//不变 j=i+1;//i不变,j变了}
所以调用这个函数,要保证自身不可变化,最终使用值返回结果。所以可以写拷贝构造一个,这就相当于int i=1,然后int j=i,然后return j=i+1。虽然可以套用上面代码,但是最巧妙的做法是复用+=。
Date Date::operator+(int day){ Date ret(*this); ret += day; return ret;}C:日期-=天数
如果是2021-2-23-=2,那么其结果为2021-2-21
如果是2021-2-23-=30,那么其结果为2021-2-(-7),但是这样的结果肯定是不合理的。所以一旦出现不合理,首先月份-1,然后天数加上此月的合理天数,那么最后结果为,2021-1-24
如果是2021-2-23-=60,其结果为2021-2-(-37),那么月份-1加上1月的合理天数变为2021-1-(-6),仍然不合理,那么月份继续-1(注意年份),加上12月的合理天数变为2020-12-25;
//日期-=天数Date& Date::operator-=(int day){ _day = _day - day; while (_day < 0) { _month--; _day = _day + GetMonthDay(_year, _month); if (_month == 0) { _month = 13; _year--; } } return *this;}D:日期-天数
这个也就不用多说了
Date Date::operator-(int day){ Date ret(*this); ret -= day; return ret;}E:前置++和后置++
前置运算符和后置运算符是C语言中讨论的较为多的话题,一个比较正确的解释是前置++是先++后 其他操作,后置++是先操作最后再++
那么对于一个自定义类型来说++d1,就要返回引用,因为是自身先要++,同样d1++,就要返回加后的结果然后再自身++
但是进行重载时,怎么区分呢。这里规定(除了this外)使用前置++无任何形参,使用后置++则表表明形参做以区别。只是为了区别,其实形参的值是不影响结果的。
//前置++Date& Date::operator++(){ (*this) += 1; return *this;}//后置++Date Date::operator++(int){ Date ret(*this); (*this) += 1; return ret;}F:前置–和后置–
这个就不用多说了
//前置--Date& Date::operator--(){ (*this) -= 1; return *this;}//后置++Date Date::operator--(int){ Date ret(*this); (*this) -= 1; return ret;}(3)运算符重载
关于C++运算符重载,都在下文中详细叙述过了,请移步
默认成员函数
A:==重载和!=重载
这是一个判断,两个日期是否相等的问题,非常简答,注意!=对==的复用
//==重载和!=重载bool Date::operator==(const Date& d){ return _year == d._year && _month == d._month && _day == d._day;}bool Date::operator!=(const Date& d){ return !((*this) == d);}B:>重载和其他重载
只要完成>重载,那么其他的重载全部依靠复用即可完成
写>重载的逻辑非常简单
//>重载bool Date::operator>(const Date& d){ if (_year > d._year) { return true; } if (_year == d._year) { if (_month > d._month) return true; if (_month == d._month) { if (_day > d._day) return true; else return false; } } return false;}
那么剩余的重载直接复用即可
//<重载 就是大于和等于取反bool Date::operator<(const Date& d){ return !((*this) == d && (*this) > d);}//>=重载 就是<重载取反bool Date::operator>=(const Date& d){ return !((*this) < d);}//<=等于重载 就是>重载取反bool Date::operator<=(const Date& d){ return !((*this) > d);}(4)日期相减
日期相减其实是一个比较麻烦的问题,需要考虑的情况非常多。有一个非常好的思路是:找到两个日期中小的那一个,然后让小的日期逐渐递增的大的日期。
标签: #c语言__date__