【类和对象】日期类总结

日期类是我们学习类和对象这部分知识的常客,本篇博客我们就对日期类成员函数进行全面总结

目录

一、一览Date.h函数声明

二、Date.cpp逐部分实现

一、流插入与流提取运算符重载

二、日期之间比较大小相等运算符重载

1.  >

2.  ==

3.  >=

4.  !=

5.  <

6.  <=

三、日期与天数运算操作符重载

1.获取某年某月的天数的函数

2.日期+=天数

3.日期+天数

4.日期-=天数

5.日期-天数

四、赋值运算符重载函数

五、日期本身运算符重载函数

1.前置++

2.后置++

3.前置--

4.后置--

5.日期-日期

 六、取地址运算符重载

七、日期类细节总结

三、日期类代码汇总(声明定义分离)

Date.h

Date.cpp

Test.cpp


一、一览Date.h函数声明

 我们将要实现的日期类关键函数分成6部分来展开讲解

#include<iostream>
using namespace std;
class Date
{//1.流插入与流提取运算符重载friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);public://获取某年某月的天数int GetMonthDay(int year, int month) const;//默认构造函数Date(int year = 1, int month = 1, int day = 1);//打印函数void Print() const; //2.日期之间比较大小相等运算符重载 //>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;//3.日期与天数运算操作符重载//日期+=天数Date& operator+=(int day);//日期+天数(复用日期+天数)Date operator+(int day) const;//日期-=天数Date& operator-=(int day);//日期-天数Date operator-(int day) const;//4.赋值运算符重载函数Date& operator=(const Date& d);//5.日期本身运算符重载函数//前置++Date& operator++();//后置++Date operator++(int);//前置--Date& operator--();//后置--Date operator--(int);//日期-日期int operator-(const Date& d) const;//6.取地址运算符重载Date* operator&();const Date* operator&()const;private:int _year;int _month;int _day;
};

二、Date.cpp逐部分实现

一、流插入与流提取运算符重载

我们已经清楚,流插入与流提取操作符平时都是这么用的:

#include<iostream>
using namespace std;
int main()
{int n = 0;cin >> n;cout << n;
}

可以看到,cin与cout都是写操作符左边的,变量在右边

而成员函数默认的this指针都是第一个形参,这就导致要把运算符重载函数设定为成成员函数的话,cin与cout的使用习惯要改变一下;

#include<iostream>
using namespace std;
class Date
{
public:void operator>>(istream& in){in >> _year >> _month >> _day;}void operator<<(ostream& out){out << _year << "年" << _month << "月" << _day << "日";}
private:int _year;int _month;int _day;
};
int main()
{Date a;a >> cin;a << cout;
}

但是这样书写cin与cout明显不符合使用习惯和价值,因此我们还是选择把流插入与流提取操作符重载成全局函数, 而全局函数又不能直接访问类中的私有成员,这时要用到友元函数的声明;

#include<iostream>
using namespace std;
class Date
{//有元函数的声明friend void operator>>(istream& in, Date& d);friend void operator<<(ostream& out, const Date& d);
private:int _year;int _month;int _day;
};
void operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;
}
void operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日";
}
int main()
{Date a;cin >> a;cout << a;
}

为了支持连续输入与输出,函数的返回值得改一改~

#include<iostream>
using namespace std;
class Date
{//有元函数的声明friend istream& operator>>(istream& in, Date& d);friend ostream& operator<<(ostream& out, const Date& d);
private:int _year;int _month;int _day;
};
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日";return out;
}
int main()
{Date a;Date b;cin >> a >> b;cout << a << endl << b;
}

二、日期之间比较大小相等运算符重载

需要实现的运算有  >   ==   >=   !=   <  <=

我们只需要具体实现前两个运算,然后其他函数复用前两个即可(充分体现this指针的价值)

1.  >

#include<iostream>
using namespace std;
class Date
{
public:bool operator>(const Date& d) const{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}else{return false;}}
private:int _year;int _month;int _day;
};

2.  ==

#include<iostream>
using namespace std;
class Date
{
public:bool operator==(const Date& d) const{if (_year == d._year && _month == d._month && _day == d._day){return true;}else{return false;}}
private:int _year;int _month;int _day;
};

3.  >=

bool Date::operator>=(const Date& d) const
{return *this > d || *this == d;
}

4.  !=

bool Date::operator!=(const Date& d) const
{return !(*this == d);
}

5.  <

bool Date::operator<(const Date& d) const
{return !(*this >= d);
}

6.  <=

bool Date::operator<=(const Date& d) const
{return !(*this > d);
}

三、日期与天数运算操作符重载

1.获取某年某月的天数的函数

 数组保存了平年每个月的天数,闰年二月直接返回29天,其余情况就返回数组中某个月天数

int GetMonthDay(int year, int month)
{const static int MonthArray[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;}return MonthArray[month];
}

2.日期+=天数

1.直接把天数加到_day上,天满了,月++,月满了,年++;

2.为了支持day为负数的操作,复用一会要实现的 -=

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 == 13){++_year;_month = 1;}}return *this;
}

3.日期+天数

日期+天数 意思是日期本身不变,返回加之后的结果,复用+=即可

Date Date::operator+(int day) const
{Date tmp(*this); //拷贝一份放到类tmp中//等价于 Date tmp = *this;tmp += day;return tmp;
}

4.日期-=天数

1.让_day减去天数,day<=0,月--,若月==0,年--,月归为12,最后_day加上该年该月天数

2.为了支持day为负数的操作,复用 +=

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

5.日期-天数

Date Date::operator-(int day) const
{Date tmp(*this);tmp -= day;return tmp;
}

四、赋值运算符重载函数

Date& Date::operator=(const Date& d)
{//避免自己给自己赋值if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}

五、日期本身运算符重载函数

1.前置++

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

2.后置++

1.后置++--加一个int参数进行占位,跟前置++构成函数重载进行区分

2.后置++返回的是++之前的值,因此我们拷贝构造了tmp保存++之前的值,返回tmp

Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}

3.前置--

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

4.后置--

Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}

5.日期-日期

 日期-日期可能是正数,也可能是负数,我们事先不知道谁大谁小,因此假定了一下~,利用变量flag标识最后的正负

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 n * flag;
}

 六、取地址运算符重载

Date* Date::operator&()
{return this; //return nullptr; ---不想被取地址
}
const Date* Date::operator&()const
{return this;
}

七、日期类细节总结

1.有的函数后面加了const,有的没有加const,取决于函数内部是否需要改变日期类,+=,-=等操作都是要改变日期类本身的,而+ - 等操作是不改变的

2.不需要在函数内部改变日期类的时候尽量都加const,否则很容易在调用时造成权限放大~

3.非const成员可以调用const函数,const成员不能调用非const函数;非const函数内部可以调用const函数, const函数内部不能调用非const函数

4.拷贝构造函数和赋值运算符重载函数本质是不一样的,都有存在的价值~

  ···拷贝构造函数是用一个已经存在的对象拷贝构造一个要创建的对象

  ···赋值运算符重载函数是把一个已经存在的对象赋值给另一个存在的对象

三、日期类代码汇总(声明定义分离)

Date.h

#include<iostream>
using namespace std;
class Date
{//友元声明friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);
public://获取某年某月的天数int GetMonthDay(int year, int month) const;//默认构造函数Date(int year = 1, int month = 1, int day = 1);//打印函数void Print() const; //加const目的是为了解决权限放大问题//总结一下:只读函数可以加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;//<=bool operator<=(const Date& d) const;//日期+=天数Date& operator+=(int day);//日期+天数(复用日期+天数)Date operator+(int day) const;//日期-=天数Date& operator-=(int day);//日期-天数Date operator-(int day) const;//赋值运算符重载函数Date& operator=(const Date& d);//前置++Date& operator++();//后置++Date operator++(int);//前置--Date& operator--();//后置--Date operator--(int);//日期-日期int operator-(const Date& d) const;//函数之间的互相调用//非const可以调用const---权限缩小//const不能调用非const---权限放大//取地址运算符重载---日常自动生成的就可以//如果不想被取到地址,可以手动实现取地址运算符重载函数Date* operator&();const Date* operator&()const;//无法重载成成员函数//流插入运算符重载函数//void operator<<(ostream& out);//流提取运算符重载函数//void operator>>(istream& in);
private:int _year;int _month;int _day;
};//void operator<<(ostream& out, const Date& d);
//void operator<<(ostream& out, const Date& d);

Date.cpp

#include "Date.h"int Date::GetMonthDay(int year, int month) const
{const static int MonthArray[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;}return MonthArray[month];
}Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;//检查日期是否合法if (month < 1 || month >12 || day > GetMonthDay(year, month)){cout << "日期非法" << endl;}
}void Date::Print() const
{cout << _year << "年" << _month << "月" << _day << "日" << endl;
}bool Date::operator>(const Date& d) const
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}else{return false;}
}bool Date::operator==(const Date& d) const
{if(_year == d._year && _month == d._month && _day == d._day){return true;}else{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);
}//+ 复用 += (效率更高) --- +的实现中有两次拷贝
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 == 13){++_year;_month = 1;}}return *this;
}Date Date::operator+(int day) const
{Date tmp(*this); //拷贝一份放到类tmp中//等价于 Date tmp = *this;tmp += day;return tmp;
}// += 复用 + (效率偏低) --- +=的实现 两次拷贝(调用+的两次拷贝) + 一次赋值 
//Date Date::operator+(int day)
//{
//	Date tmp(*this);
//	tmp._day += day;
//	while (tmp._day > GetMonthDay(_year, _month))
//	{
//		tmp._day -= GetMonthDay(_year, _month);
//		++tmp._month;
//		if (tmp._month == 13)
//		{
//			++tmp._year;
//			tmp._month = 1;
//		}
//	}
//	return tmp;
//}
//
//Date& Date::operator+=(int day)
//{
//	法一:
//	//Date ret = *this + day;
//	//*this = ret; //赋值重载
//
//	//法二:
//	*this = *this + day; //赋值重载
//	return *this;
//}
/Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}Date Date::operator-(int day) const
{Date tmp(*this);tmp -= day;return tmp;
}//赋值运算符重载函数---返回值可以是void, 但最好是Date&, 这样才能支持连续赋值
Date& Date::operator=(const Date& d)
{//避免自己给自己赋值if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}//前置++
Date& Date::operator++()
{*this += 1;return *this;
}//后置++--加一个int参数进行占位,跟前置++构成函数重载进行区分
//本质后置++调用,编译器进行特殊处理
Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
//后置--
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}//日期-日期
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 n * flag;
}//取地址运算符重载函数
Date* Date::operator&()
{return this; //return nullptr; ---不想被取地址
}
const Date* Date::operator&()const
{return this;
}//不太符合使用习惯的写法
流插入运算符重载函数
//void Date::operator<<(ostream& out)
//{
//	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
//}
//
流提取运算符重载函数
//void Date::operator>>(istream& in)
//{
//	in >> _year >> _month >> _day;
//}//有元函数写法
//流插入运算符重载函数
//void operator<<(ostream& out, const Date& d)
//{
//	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
//}
流提取运算符重载函数
//void operator>>(istream& in, Date& d)
//{
//	in >> d._year >> d._month >> d._day;
//}//支持连续的流插入与流提取
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}
//流提取运算符重载函数
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

Test.cpp

#include "Date.h"
void TestDate1() //测试运算符重载函数
{Date d1(2023, 7, 23);Date d2(2023, 8, 1);cout << (d1 > d2) << endl; //等价于 d1.operator>(d2);cout << (d1 == d2) << endl; //等价于 d1.operator==(d2);cout << (d1 >= d2) << endl; //等价于 d1.operator>=(d2);cout << (d1 != d2) << endl; //等价于 d1.operator!=(d2);cout << (d1 < d2) << endl; //等价于 d1.operator<(d2);cout << (d1 <= d2) << endl; //等价于 d1.operator<=(d2);
}void TestDate2() //测试 += 与 +
{//+=Date d1(2023, 7, 23);Date ret1 = d1 += 150;ret1.Print();//+Date d2(2023, 8, 1);Date ret2 = d2 + 33; //等价于Date ret2(d7 + 33);ret2.Print();
}void TestDate3() //测试 -= 与 -
{//-=Date d1(2023, 7, 23);Date ret1 = d1 -= 33;ret1.Print();//-Date d2(2023, 1, 13);Date ret2 = d2 - 23;ret2.Print();
}void TestDate4() // 测试 += -= + - 负数
{Date d1(2023, 8, 1);Date ret1 = d1 += -100;ret1.Print();Date d2(2023, 8, 1);Date ret2 = d2 -= -100;ret2.Print();
}void TestDate5() //测试拷贝构造函数与赋值运算符重载函数
{//拷贝构造和赋值重载是有区别的//拷贝构造:一个已经存在的对象去初始化另一个要创建的对象Date d3(2023, 7, 31);Date d4(d3);//赋值重载:两个已存在对象进行拷贝Date d5(2023, 8, 1);Date d6;d6 = d5; //等价于d6.operator=(d5);//连续赋值d3 = d6 = d5; // d6 = d5 表达式的返回值是d6d3.Print();
}void TestDate6() //测试前置++,后置++,前置--,后置--
{Date d1(2023, 7, 31);Date ret1 = ++d1;  //可以显式调用 Date ret1 = d1.operator++();d1.Print();ret1.Print();Date d2(2023, 7, 31);Date ret2 = d2++;//可以显式调用 Date ret2 = d2.operator++(int);d2.Print();ret2.Print();Date d3(2023, 7, 31);Date ret3 = --d3;d3.Print();ret3.Print();Date d4(2023, 7, 31);Date ret4 = d4--;d4.Print();ret4.Print();
}void TestDate7() //测试日期-日期
{Date d1(2023, 8, 1);Date d2(2004, 3, 19);cout << d1 - d2 << endl;
}void TestDate8() //测试权限问题
{const Date d1; d1.Print();  //权限平移Date d2;d2.Print();  //权限缩小
}void TestDate9() //测试取地址运算符重载函数
{Date d1(2023, 8, 1);cout << &d1 << endl; //编译器调用了取地址运算符重载const Date d2(2023, 8, 2);cout << &d2 << endl; //编译器调用了取地址运算符重载
}void TestDate10() //测试流插入与流提取重载函数
{测试流提取//Date d1(2023, 8, 1);cout << d1; //如何直接使用 << 输出自定义类型对象 ---运算符重载函数//d1 << cout;测试流插入//Date d2;//d2 >> cin;//d2 << cout;//上述写法虽然可以,但是不符合使用习惯和价值//友元函数~//Date d3;//cin >> d3;//cout << d3;//连续插入&连续提取Date d4;Date d5;cin >> d4 >> d5;cout << d4 << d5;
}int main()
{TestDate1();TestDate2();TestDate3();TestDate4();TestDate5();TestDate6();TestDate7();TestDate8();TestDate9();TestDate10();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/54343.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac前端代码编辑 Sublime Text 4 Dev 中文v4.0(4151)

Sublime Text 4 for Mac是一款功能强大的代码编辑器&#xff0c;适合所有需要高效编写代码和进行代码管理的程序员使用。 快速响应&#xff1a;Sublime Text 4在加载文件和执行命令时非常快速&#xff0c;能够让用户在高效的开发过程中体验到无缝的交互。 多种语言支持&#…

LNMP搭建

LNMP&#xff1a;目前成熟的企业网站的应用模式之一&#xff0c;指的是一套协同工作的系统和相关软件 能够提供静态页面服务&#xff0c;也可以提供动态web服务。 这是一个缩写 L linux系统&#xff0c;操作系统。 N nginx网站服务&#xff0c;也可也理解为前端&#xff0c…

STM32——STM32F401x系列标准库的下载+环境搭建+建工程步骤(更完整)

文章目录 标准库的下载环境搭建建工程最后的话 标准库的下载 1.STM32标准库的官网下载网站https://www.st.com/content/st_com/en.html 2. 3. 4. 5. 6. 7.点击之后下滑 8.选择自己需要的版本下载 环境搭建建工程 大致步骤同之前我写的一篇STM32——建工程差不多&#xff0…

记录下:win10 AMD CPU 下载 Chromium 源码并编译(版本 103.0.5060.66)

文章目录 一、一些主要地址连接二、环境配置1、如何找官方环境文档&#xff1a;1.1 如何找到这个不同版本的文档&#xff1a; 2、电脑配置&#xff1a;3、visual studio 2019安装&#xff1a;3.1 社区版下载&#xff1a;3.2 安装配置&#xff1a; 4、debugtools配置4.1 如何判断…

webpack基础知识八:说说如何借助webpack来优化前端性能?

一、背景 随着前端的项目逐渐扩大&#xff0c;必然会带来的一个问题就是性能 尤其在大型复杂的项目中&#xff0c;前端业务可能因为一个小小的数据依赖&#xff0c;导致整个页面卡顿甚至奔溃 一般项目在完成后&#xff0c;会通过webpack进行打包&#xff0c;利用webpack对前…

【Linux】冯诺伊曼体系结构|操作系统概念理解

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;Linux仓库 个人专栏&#xff1a;Linux专栏 分享一句喜欢的话&#xff1a;热烈的火焰&#xff0c;冰封在最沉默的火山深处 文章目录 前言一、先谈硬件——冯诺依曼体系结构1.什么是冯诺依曼体系结构&am…

sql 关联了2张表的 update 语句(转)

转自&#xff1a;SQL Update&#xff1a;使用一个表的数据更新另一张表 、update 关联两个表 基本上 select 能支持的关联和子查询操作&#xff0c;都能在 update 语句中使用。 在 where 条件中使用子查询 update a set a.age 1 where id in (select device_id from b) 在 wher…

shell 脚本

一、使用PID过滤该进程的所有信息 #! /bin/bash # Function: 根据用户输入的PID&#xff0c;过滤出该PID所有的信息 read -p "请输入要查询的PID: " P nps -aux| awk $2~/^$P$/{print $11}|wc -l if [ $n -eq 0 ];thenecho "该PID不存在&#xff01;&#xff0…

Flink开发环境准备: centos-jdk8

linux-jdk8 - Flink开发环境准备 一、基本介绍二、环境准备1.1 JDK环境1.2 开发工具1.3 Maven环境 三、flink下载安装配置3.1 Flink下载3.2 flink本地模式安装 - linux3.3 常用配置3.4 日志的查看和配置 四、单机 Standalone 的方式运行 Flink 一、基本介绍 Flink底层源码是基于…

CSS元素的显示模式

1、现在我想做成小米左侧边栏这样的效果&#xff0c;该怎么做呢&#xff1f; 2、小米商城触碰之后会显示出新的商品案例 3、一碰到之后会出现这个列表 4、这里涉及到了元素显示模式&#xff1a; 5、用人进行划分可以分为男人和女人&#xff0c;根据男人和女人的特性进行相应的…

Kill OOM

1、什么是OOM&#xff1f; OOM是每个程序员早晚都必须面对的问题&#xff0c;通常情况下&#xff0c;Java程序员所说的OOM是JVM OOM,即java.lang.OutOfMemoryError&#xff0c;是指Java程序在运行时申请内存超过JVM可用内存限制&#xff0c;导致JVM无法继续分配内存&#xff0…

【Spring框架】Spring事务

目录 Spring中事务的实现编程式事务声明式事务Transactional 作⽤范围Transactional 参数说明注意事项Transactional ⼯作原理 MySQL 事务隔离级别Spring 事务隔离级别事务传播机制 Spring中事务的实现 Spring中事务操作分为两类&#xff1a; 1.编程式事务 2.声明式事务 编程…