【C++】类和对象练习——日期类的实现

实现功能:

1.h文件:Date类内:

内联函数:

  • 检查日期是否合法
    //检查日期是否合法的函数
    bool CheckDate()
    {if (_month < 1 || _month>12|| _day< 1 || _day>GetMonthDay(_year, _month)){return false;}}
  • 获取每个月的天数
    //获取每个月的天数——该函数使用最为频繁,故直接放到类里作内联函数。int GetMonthDay(int year, int month){//保证月份在正确的区间assert(month > 0 || month < 13);//把数组放到静态区//原因:由于频繁调用,为避免其每次进入函数都反复创建空间static int MonthArr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };//将第0个位置空出来//闰年的二月情况单独if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){return 29;}return MonthArr[month];}
  • 友元函数(以便全局函数(流输入输出函数)使用私有)
    	//友元函数的声明:// 作用:可以在类访问私有friend ostream& operator<<(ostream& out, const Date& d);//流输出friend istream& operator>>(istream& in, Date& d);//流输入//流输入这里是不能加const的,因为我们提取的值要写到对象d里面去
    

2.cpp文件:具体功能实现

  • 运算符重载功能:比较大小
    //运算符重载功能
    // operator传值注意:
    // d1(对应operator)的地址,d2(对应参数列表第一个参数)的地址//比较大小
    //应学会的技巧:复用函数~
    bool Date::operator > (const Date& d)
    {//从day开始比较//天大就大if(_day > d._day){return true;}//天相等,月大就大else if(_day == d._day && _month > d._month){return true;}//天、月相等,年大就大else if (_day == d._day && _month == d._month && _year > d._year){return true;}return false;
    }bool Date::operator == (const Date& d)
    {return _day == d._day && _month == d._month && _year == d._year;
    }// == 的函数取反(!),就是 != 的函数
    bool Date::operator != (const Date& d)
    {return !(*this == d);
    }// d1 >= d2
    //this是d1的地址,d是d2的地址
    // 
    // >= 重载,直接结合 > 和 = 的运算符重载函数 
    bool Date::operator >= (const Date& d)
    {//注意:此处的this是指针,改变其数值要使用*this//      而d是引用,改变值直接使用dreturn *this > d || *this == d;
    }// >= 的函数取反(!),就是 < 的函数
    bool Date::operator < (const Date& d)
    {return !(*this >= d);
    }// > 的函数取反(!),就是 < 的函数
    bool Date::operator <= (const Date& d)
    {return !(*this > d);
    }
  • 日期类加减
    //日期类的加减
    //日期加日期无意义,日期加整型(如天数)有意义// += 是天数直接赋值到对象,会改变对象的值,故使用引用Date&
    // + 是算以后多少天的日期,不改变数值,故直接Date
    Date& Date::operator += (int day)
    {//d1 += -100, d1 = d1-100if (day < 0){//d1 - (-100) = d1 + 100return *this -= -day;}_day += day;//天数大于当月天数while (_day > GetMonthDay(_year, _month)){//月份进一位,天数减掉当月天数_day -= GetMonthDay(_year,_month);++_month;//月份大于12,说明这一年过去了if (_month == 13){//年份进一位,月份更新为来年一月_year++;_month = 1;}}return *this;
    }//此前提是已经有+= 运算符重载函数
    //注意: + 是不改变对象的
    Date Date::operator + (int day)
    {//调用拷贝构造,拷贝this指向的对象Date tmp = *this;//赋值给tmptmp += day;//返回tmp,不会改变原对象的值return tmp;
    }Date& Date::operator -= (int day)
    {//d1 -= -100 ,d1 = d1 + (-100)if (day < 0){//d1 + (-100) == d1 - 100; return *this += -day;}//原来的天数减去要减的天数_day -= day;while (_day <= 0){-- _month;if (_month == 0){//说明到上一年12月了--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
    }//原理同上 +
    Date Date::operator - (int day)
    {//拷贝构造Date tmp (*this);tmp -= day;//利用上面实现的 -=return tmp;
    }
    
  • 日期前置后置++--
    	//日期前置与后置++--//前置++ 返回++后的值,即直接返回改变值后的对象,用引用
    Date& Date::operator++()
    {*this += 1;return *this;
    }
    //后置++ 返回++前的值,即用一个拷贝对象 拷贝改变值前的值返回,
    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)
    {//传入默认 d1 - d2Date max = *this;//默认假设d1大Date min = d;int flag = 1;if (*this < d){//此时d1 - d2 是负数,故flag要变-1 避免返回负数max = d;min = *this;flag = -1;}//计数器countint count = 0;while (min != max){min++;count++;}return count * flag;//避免返回负数
    }​
  • 日期自定义格式流输出和输入
    ​//流输出
    ostream& operator <<(ostream& out, const Date& d)
    {out << d._year << "年" << d._month << "日" << d._day << "日" << endl;
    }
    //流输入
    istream& operator >> (istream& in,Date& d)
    {//这里要注意输入的日期可能不合法while (1)//用循环,直至输入合法日期可跳出循环{cout << "请输入正确的日期:" << endl;in >> d._year >> d._month >> d._day;if (d.CheckDate()){break;}else{cout << "日期非法,请重新输入" << endl;}}return in;
    }​

具体代码:

Date.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<assert.h>
using namespace std;class Date
{
public://友元函数的声明:// 作用:可以在类访问私有friend ostream& operator<<(ostream& out, const Date& d);//流输出friend istream& operator>>(istream& in, Date& d);//流输入//流输入这里是不能加const的,因为我们提取的值要写到对象d里面去Date(int year = 1999, int month = 1, int day = 1);void print();//检查日期是否合法的函数bool CheckDate(){if (_month < 1 || _month>12|| _day< 1 || _day>GetMonthDay(_year, _month)){return false;}}//获取每个月的天数——该函数使用最为频繁,故直接放到类里作内联函数。int GetMonthDay(int year, int month){//保证月份在正确的区间assert(month > 0 || month < 13);//把数组放到静态区//原因:由于频繁调用,为避免其每次进入函数都反复创建空间static int MonthArr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };//将第0个位置空出来//闰年的二月情况单独if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){return 29;}return MonthArr[month];}
//————————————————————————————————————————————————————————//运算符重载功能//比较大小bool operator > (const Date& d);bool operator < (const Date& d);bool operator >= (const Date& d);bool operator <= (const Date& d);bool operator == (const Date& d);bool operator != (const Date& d);//————————————————————————————————————————————————————————
//日期类的加减
//日期加日期无意义,日期加整型(如天数)有意义// += 是天数直接赋值到对象,会改变对象的值,故使用引用Date&
// + 是算以后多少天的日期,不改变数值,故直接DateDate& operator += (int day);Date operator + (int day);Date& operator -= (int day);Date operator - (int day);//————————————————————————————————————————————————————————//日期前置与后置++--//前置++ 返回++后的值,即直接返回改变值后的对象,用引用Date& operator++();//后置++ 返回++前的值,即用一个拷贝对象 拷贝改变值前的值返回,Date operator++(int);//原理同上Date& operator--();Date operator--(int);
//————————————————————————————————————————————————————————
//两个日期相减int operator-(const Date& d);//————————————————————————————————————————————————————————
//流输出和流输入//即需要重载<< >>,此时重载必须为全局函数//若重载为成员函数,this指针默认抢占第一个形参位置,即变成 this对象 << cout//而我们正常应该是 cout << this对象//注意:由于是在全局函数,无法访问类内私有的_year _month _day//此时我们在Date类开头加友元函数声明这个全局函数(即流输入输出函数)//————————————————————————————————————————————————————————
private:int _year;int _month;int _day;
};//流输出
ostream& operator <<(ostream& out, const Date& d);//流输入
//流输入这里传参列表是不能加const的,因为我们提取的值要写到对象d里面去
istream& operator >>(istream& in,Date& d);

Date.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"//Date:: 的作用 
// 在某个类的外面定义它的成员函数,要指定类域,否则无法知道是否是某个类的成员函数
//即不知道你_year那些是哪来的(它默认只在全局找,不特定标明他不会特地去类域找)//为啥声明里(Date.h)有缺省值,定义(Date.cpp)没有?
// (参数列表中初始定义传入的参数为某个数值,如 int year = 10)
// 复习一下!缺省值 在声明和定义都存在时,只在声明中标明。
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}//注:Date::在函数名前加!别在返回值前加!
void Date::print()
{cout << _year << "-" << _month << "-" << _day << endl;
}//————————————————————————————————————————————————————————
//运算符重载功能
// operator传值注意:
// d1(对应operator)的地址,d2(对应参数列表第一个参数)的地址//比较大小
//应学会的技巧:复用函数~
bool Date::operator > (const Date& d)
{//从day开始比较//天大就大if(_day > d._day){return true;}//天相等,月大就大else if(_day == d._day && _month > d._month){return true;}//天、月相等,年大就大else if (_day == d._day && _month == d._month && _year > d._year){return true;}return false;
}bool Date::operator == (const Date& d)
{return _day == d._day && _month == d._month && _year == d._year;
}// == 的函数取反(!),就是 != 的函数
bool Date::operator != (const Date& d)
{return !(*this == d);
}// d1 >= d2
//this是d1的地址,d是d2的地址
// 
// >= 重载,直接结合 > 和 = 的运算符重载函数 
bool Date::operator >= (const Date& d)
{//注意:此处的this是指针,改变其数值要使用*this//      而d是引用,改变值直接使用dreturn *this > d || *this == d;
}// >= 的函数取反(!),就是 < 的函数
bool Date::operator < (const Date& d)
{return !(*this >= d);
}// > 的函数取反(!),就是 < 的函数
bool Date::operator <= (const Date& d)
{return !(*this > d);
}//————————————————————————————————————————————————————————
//日期类的加减
//日期加日期无意义,日期加整型(如天数)有意义// += 是天数直接赋值到对象,会改变对象的值,故使用引用Date&
// + 是算以后多少天的日期,不改变数值,故直接Date
Date& Date::operator += (int day)
{//d1 += -100, d1 = d1-100if (day < 0){//d1 - (-100) = d1 + 100return *this -= -day;}_day += day;//天数大于当月天数while (_day > GetMonthDay(_year, _month)){//月份进一位,天数减掉当月天数_day -= GetMonthDay(_year,_month);++_month;//月份大于12,说明这一年过去了if (_month == 13){//年份进一位,月份更新为来年一月_year++;_month = 1;}}return *this;
}//此前提是已经有+= 运算符重载函数
//注意: + 是不改变对象的
Date Date::operator + (int day)
{//调用拷贝构造,拷贝this指向的对象Date tmp = *this;//赋值给tmptmp += day;//返回tmp,不会改变原对象的值return tmp;
}Date& Date::operator -= (int day)
{//d1 -= -100 ,d1 = d1 + (-100)if (day < 0){//d1 + (-100) == d1 - 100; return *this += -day;}//原来的天数减去要减的天数_day -= day;while (_day <= 0){-- _month;if (_month == 0){//说明到上一年12月了--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}//原理同上 +
Date Date::operator - (int day)
{//拷贝构造Date tmp (*this);tmp -= day;//利用上面实现的 -=return tmp;
}//————————————————————————————————————————————————————————//日期前置与后置++--//前置++ 返回++后的值,即直接返回改变值后的对象,用引用
Date& Date::operator++()
{*this += 1;return *this;
}
//后置++ 返回++前的值,即用一个拷贝对象 拷贝改变值前的值返回,
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)
{//传入默认 d1 - d2Date max = *this;//默认假设d1大Date min = d;int flag = 1;if (*this < d){//此时d1 - d2 是负数,故flag要变-1 避免返回负数max = d;min = *this;flag = -1;}//计数器countint count = 0;while (min != max){min++;count++;}return count * flag;//避免返回负数
}//————————————————————————————————————————————————————————//流输出
ostream& operator <<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "日" << d._day << "日" << endl;
}
//流输入
istream& operator >> (istream& in,Date& d)
{//这里要注意输入的日期可能不合法while (1)//用循环,直至输入合法日期可跳出循环{cout << "请输入正确的日期:" << endl;in >> d._year >> d._month >> d._day;if (d.CheckDate()){break;}else{cout << "日期非法,请重新输入" << endl;}}return in;
}

Test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"int main()
{//Date d1(2024, 8, 10);//d1.Print();//2024-8-10///*d1 += 100;//d1.Print();*///2024-11-18//Date d2 = d1 + 100;//d2.Print();//d1.Print();//那么这里的d1就没有被改变了///*int i = 1;//i + 100;*////*//如果是单纯的+的话,原先的对象是不会被改变的,但是现在我们的对象已经被改变了//由此可知我们在这里实现的是+=的操作符//*///d1 += 100; //d1.Print();//d1 -= 100;//d1.Print();//Date ret1=++d1;//d1.Print();//Date ret2 = d1++;//d1.Print();//ret1.Print();//ret2.Print();Date d1(2024, 2, 29);Date d2(2024, 8, 20);cout << d1 - d2 << endl;cout << d2 - d1 << endl;/*cout << d1;*//*d1 << cout;*///我们只有这么写才能正确打印出来日期//d1对应的就是隐含的this指针,cout对应的就是后面的参数//但是这种写法很怪//那么我们是否有方法将这个进行改变呢/*重载<<和>>时,需要重载为全局函数然后我们的ostream/iostream就能放到第一个参数了然后第二个参数就是我们的对象了*/cout << d1; operator<<(cout, d1);//本质//那么到这里我们就不支持了cout << d1<<d2<<endl;//我们这里是从左往右进行结合//对于cout << d1这个我们的返回值应该是cout 然后cout和d2//再次返回cout 和endl//所以流插入是需要返回cout的cin >> d1 >> d2;cout << d1 << d2 << endl;return 0;
}

希望对你有帮助

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

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

相关文章

MATLAB锂电概率分布模型

&#x1f3af;要点 概率分布等效电路模型结合了路径相关速率能力及状态估计中滞后效应。纠正了充电状态中时间误差累积及避免开路电压中电压滞后现象。使用电流方向和电池容量相关函数描述开路电压&#xff0c;并使用微分方程描述电压滞后现象。模型结构基于一级相变的材料机制…

Nginx - 缓慢的 HTTP 拒绝服务攻击

参考链接 https://zhuanlan.zhihu.com/p/677536047 【网络安全】HTTP Slowloris攻击原理解析-CSDN博客 缓慢的http拒绝服务攻击 - 二月无雨 - 博客园 Nginx解决Http慢攻击(Slow HTTP Attack)_nginx 慢拒绝服务攻击-CSDN博客 解决方案 在 nginx.conf 中 http 块里面配置&am…

QT界面开发--我的第一个windows窗体【菜单栏、工具栏、状态栏、铆接部件、文本编辑器、按钮、主界面】

经过前面的铺垫&#xff0c;今天我们就开始我们图形化界面之旅了&#xff0c;我们的第一个窗体主要包括&#xff1a;菜单栏、状态栏、工具栏、铆接部件、还有Qt提供的一些主窗体的API。 第一部分&#xff1a;主界面(QMainWindow) 当创建好项目后&#xff0c;我们直接运行&…

网络安全领域推荐职位

网络安全领域提供了多种多样的职位&#xff0c;每个职位都有其独特的职责和技能要求。以下是几个具体的推荐职位&#xff0c;适合网络安全工程师以及希望在物联网安全方面有所发展的专业人士&#xff1a; 1. 网络安全分析师&#xff08;Security Analyst&#xff09; 职责&am…

Unity中的动画状态机(详解)

动画状态机的定义 Unity中的动画状态机&#xff08;Animator Controller&#xff09;是用于定义和管理角色或对象动画状态之间转换的工具。它允许动画师和开发者设计复杂的动画逻辑&#xff1b; 例如角色的行走、跑步、跳跃、攻击等动作&#xff0c;以及其他动作之间的平滑过渡…

Vue笔记-element ui中关于table的前端分页

对于 Element UI 表格的前端分页&#xff0c;可以在组件中使用 JavaScript 来实现数据的分页显示&#xff0c;而不必从后端获取已分页的数据。以下是一个简单的示例&#xff0c;演示如何在前端进行 Element UI 表格的分页&#xff1a; <template><div><el-tabl…

ShellCode 格式化代码注入工具

一款基于C/C开发的应用层汇编代码注入工具&#xff0c;可实现向特定进程内注入动态链接库模块或注入ShellCode汇编指令集&#xff0c;还可以实现第三方进程的汇编级Call调用&#xff0c;通常被用于协助渗透人员完成内存注入&#xff0c;同时也可用于对特定ShellCode汇编代码进行…

Ubuntu系统安装软件

在Linux系统中有四种软件安装方式&#xff1a;rpm、yum、apt、编译安装 编译安装 编译安装只有一个源码包&#xff0c;源码包是由一大堆源代码程序组成的&#xff0c;是由程序员按照特定格式和语法编写好了&#xff0c;现成的安装包 程序&#xff1a;未执行的代码 进程&#…

关于前端div里面内嵌滚动条的使用

怀旧网个人博客网站&#xff1a;怀旧网&#xff0c;博客详情&#xff1a;关于前端div里面内嵌滚动条的使用 使用方法 需要完成这个效果&#xff0c;只需要在div里面加上一个属性就可以。设置css属性&#xff1a;overflow: auto; 就可以实现-代码如下&#xff1a; <div id…

`a = a + b` 与 `a += b` 的区别

在 Java 中&#xff0c;a a b 和 a b 都用于将 b 的值加到 a 上&#xff0c;但它们之间存在一些重要的区别&#xff0c;尤其是在类型转换和操作行为方面。 使用 操作符时&#xff0c;Java 会自动进行隐式类型转换&#xff0c;而使用 则不会。这意味着在 a b 的情况下&am…

雷池社区版compose配置文件解析-mgt

在现代网络安全中&#xff0c;选择合适的 Web 应用防火墙至关重要。雷池&#xff08;SafeLine&#xff09;社区版免费切好用。为网站提供全面的保护&#xff0c;帮助网站抵御各种网络攻击。 compose.yml 文件是 Docker Compose 的核心文件&#xff0c;用于定义和管理多个 Dock…

自动驾驶-传感器简述

自动驾驶车辆上的传感器类型包含激光雷达、毫米波雷达、相机、imu、rtk、超声波雷达等&#xff0c;这些传感器用来接收外部世界多姿多彩的信号&#xff0c;根据接收到的信号&#xff0c;车载大脑对信号进行处理&#xff0c;那信号的准确程度就尤为重要。 本文将各个传感器的特性…

MNIST 数据集的CSV的格式的使用(SNN)

1&#xff1a; 利用spikingjelly 实现MNIST 数据集分类 设置仿真时间T10 import time import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import DataLoader, TensorDataset from spikingjelly.activation_based import neuron, en…

java常用数据结构及其接口

Java 提供了丰富的集合框架及其数据结构&#xff0c;每个结构和接口都有独特的功能。以下是一些常用的数据结构和接口&#xff0c;以及它们的关键方法&#xff1a; ### 接口及其实现 1. **List 接口** - 实现类&#xff1a;ArrayList、LinkedList、Vector - 关键方法&a…

git合并相关操作详解

在使用Git进行分支管理时,合并(merge)操作是非常常见的。下面是Git合并相关的详细步骤和一些常见的场景及注意事项。 一、 基本合并操作 假设我们有两个分支:main 和 feature,希望将 feature 合并到 main 上。 切换到目标分支 首先需要切换到你想合并到的分支。例如,切…

Lucas带你手撕机器学习——岭回归

岭回归&#xff08;Ridge Regression&#xff09; 一、背景与引入 在进行线性回归分析时&#xff0c;我们常常面临多重共线性的问题。多重共线性指的是自变量之间高度相关&#xff0c;这会导致回归系数的不稳定性&#xff0c;使得模型的预测能力降低。传统的线性回归通过最小…

模块化主动隔振系统市场规模:2023年全球市场规模大约为220.54百万美元

模块化主动隔振系统是一种用于精密设备和实验装置的隔振解决方案&#xff0c;通过主动控制技术消除振动干扰&#xff0c;提供稳定的环境。目前&#xff0c;随着微纳制造和精密测量技术的发展&#xff0c;对隔振系统的要求越来越高。模块化设计使得系统能够灵活适应不同负载和工…

STM32 第3章 如何用串口下载程序

时间:2024.10.28 一、学习内容 1、安装USB转串口驱动 1.1串口下载连接示意图 1、USB转串口模块在开发板上是一个独立的模块,可通过调帽与其他串口连接,USART1/2/3/4/5 2、只有USART1才具有串口下载的功能。 3、CH340是电平转换芯片,将电脑端输出的USB电平和单片机输…

移除字符串中空格_Java实现

package com.leetcode;/*** 移除字符串中空格*/ public class RemoveSpaceFromStr {public static String removeWhiteSpaceFromStr(String input){StringBuilder outputnew StringBuilder();char[] charsinput.toCharArray();for (char c : chars) {if(!Character.isWhitespac…

1.3 面向对象 C++面试问题

1.3.1 简述一下什么是面向对象,面向对象与面向过程的区别 什么是面向对象 面向对象&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是一种编程范式&#xff0c;它通过将现实世界中的实体抽象为“对象”来组织代码。面向对象编程关注对象及其交互&#x…