当前位置: 首页 > news >正文

C++项目实战(日期类的实现)

🎈 个人主页👉:tbRNA-CSDN博客tbRNA-CSDN博客tbRNA-CSDN博客

💯 个人简介:在校大学生一枚💋.
😍 希望我的文章对大家有着不一样的帮助,欢迎大家关注我,感谢大家的多多支持!

🎉 欢迎  👍点赞  ✍评论  ⭐收藏

类与对象往期文章👇   

C++基础知识点(五)

C++基础知识点(四)

C++基础知识点(三)

C++基础知识点(二)

C++基础知识点(一)

目录

第一部分: Date.h 

第二部分: Date.cpp

第三部分: Test.cpp

第四部分:总结


☺️ 今天带来一个日期类项目的实战,主要是针对类与对象这部分内容进行复习与总结。
日期类项目结构分为三个部分:
1. Date.h(函数的声明)
2. Date.cpp(函数的定义)
3. Test.cpp(主函数)

第一部分: Date.h 

#pragma once#include <iostream>
#include <assert.h>
using namespace std;class Date
{
public:// 输入检查bool CheckOut();// 构造函数Date(int year, int month, int day);// 输出函数void Print();// 获取天数(默认是内联)int GetMonthDay(int year, int month){assert(month > 0 && month < 13);static int MonthDayArray[13] = { -1, 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 MonthDayArray[month];}// "+"的运算符重载Date operator+(int day);// "+="的运算符重载Date& operator+=(int day);// "-"的运算符重载Date operator-(int day);// "-="的运算符重载Date& operator-=(int day);// "后置++"的运算符重载Date operator++(int);// "前置++"的运算符重载Date& operator++();// "后置--"的运算符重载Date operator--(int);// "前置--"的运算符重载Date& operator--();// "<"的运算符重载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);// "-"两个日期相减int operator-(const Date& d);private:int _year;int _month;int _day;
};

重点来说几个知识点:

一.  int GetMonthDay(int year, int month) 这个函数因为需要频繁调用(获取当月天数),因此把他放在类内定义默认为内联函数(inline),这样调用函数的过程就可以直接执行函数代码,而不发生跳转、压栈等一般性函数操作,因此可以节省时间,也会提高程序的执行速度。

😛 复习一下内联函数(inline)

1. 内联函数的定义
inline 关键字是C99标准的型关键字,其作用是:

① 将函数展开,把函数的代码复制到每一个调用处。

② 这样调用函数的过程就可以直接执行函数代码,而不发生跳转、压栈等一般性函数操作。

③ 可以节省时间,也会提高程序的执行速度。

2. 内联函数的使用

① 关键字 inline 的使用是有所限制的:

inline 只适合函数体内代码比较简单的函数使用,不能包含复杂的结构控制语句,例如while、switch,并且内联函数本身不能是直接递归函数(函数内部调用自己的函数)。

② inline 仅是一个对编译器的建议:

inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,需要看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。

③ 建议把 inline 函数的定义放在头文件中:

因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。

所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义

因此,将内联函数的定义放在头文件里实现是合适的,避免每个文件实现一次的麻烦。

 inline  不建议声明和定义分离到两个⽂件,分离会导致链接错误。

因为inline被展开,就没有函数地址,链接时会出现报错,因此需要定义 inline函数 在头文件。

3. 内联函数的优缺点 

😜优点: 普通函数在调用过程中,会对寄存器中内容进行上下文切换(比如push和pop操作),而内联函数则不需要,所以普通函数相比内联函数,耗时要多一些

🫢 缺点:当函数使用次数比较多的时候,内联函数在每个调用的地方都会被展开,所以导致固件大小会变大,同一段代码会多次重复出现在固件中。而普通函数则没有此问题,不管调用的函数的次数多少,函数在固件中均只占用一处,空间利用率较高。

因此,inline函数其实就是空间换时间

int GetMonthDay(int year, int month)
{assert(month > 0 && month < 13);static int MonthDayArray[13] = { -1, 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 MonthDayArray[month];
}

二.  GetMonthDay函数好用的点在于:

1.  首先先对传入的month进行判断,避免输入错误。

2. 采用静态static创建一个月天数数组。

🤔 复习一下static:

1. static是静态修饰符,由其关键字修饰的变量会保存到全局数据区

① 对于普通的局部变量或者全局变量,都是由系统自动分配内存的,并且当变量离开作用域的时候释放掉。

② 而使用 static 关键字来修饰,只有当程序结束时候才会释放掉。

那么staticinline函数(内联)结合使用的好处是什么呢?

① 使用static inline修饰时,函数仅在文件内部可见,不会污染命名空间。

② 函数在运行过程中也会分配内存空间,但是由于static的存在(和修饰变量类似),它只会开辟一块内存空间。

😏 月天数数组的元素个数为13个,避免第0月的错误,保证了正确月份的顺序 。

对于闰年的2月份,则采用单独进行闰年判断处理:

if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))return 29;

三.   将对象进行引用返回,减少值拷贝

// "+="的运算符重载
Date& operator+=(int day);
// "-="的运算符重载
Date& operator-=(int day);
// "前置++"的运算符重载
Date& operator++();
// "前置--"的运算符重载
Date& operator--();

第二部分: Date.cpp

#include "Date.h"bool Date::CheckOut()
{if (_month < 1 || _month > 12 || _day < 1 || _day > GetMonthDay(_year, _month)){return false;}else{return true;}
}Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (!CheckOut()){cout << "非法日期:";Print();}
}void Date::Print()
{cout << _year << "-" << _month << "-" << _day << endl;
}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)
{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)
{Date tmp = *this;tmp += day;return tmp;
}Date Date::operator-(int day)
{Date tmp = *this;tmp -= day;return tmp;
}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;
}Date& Date::operator--()
{*this -= 1;return *this;
}bool Date::operator<(const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year){if (_month < d._month){return true;}else if (_month == d._month){if (_day < d._day){return true;}}}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);
}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);
}

😋Date.cpp 这部分代码是对头文件声明的函数进行定义

我们可以看到:

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)
{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)
{Date tmp = *this;tmp += day;return tmp;
}Date Date::operator-(int day)
{Date tmp = *this;tmp -= day;return tmp;
}

🥸在对" += "  " + " ,以及 " -= 和 " - 这些运算符重载中,可以直接调用已定义的运算符进行重载,比如 "" 运算符可以调用 " += " 运算符," -= " 运算符可以调用 " - " 运算符。

🥳相对于已经定义好的" + "和" - "," += " 也可以调用 " + "," -= " 也可以调用 " - " 。

bool Date::operator<(const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year){if (_month < d._month){return true;}else if (_month == d._month){if (_day < d._day){return true;}}}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);
}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);
}int Date::operator-(const Date& d)
{Date max = *this;Date min = d;int flag = 1;if (*this < d){flag = -1;max = d;min = *this;}int n = 0;while (min != max){++min;++n;}return flag * n;
}

🤪同时从上面代码我们也可以看到,这么多函数定义中我们只需要详细写其中一两个,其他的函数定义都可以直接调用已定义的函数,实现了代码的简洁高效。

整个日期类实现中重点函数是:

1. 日期加天数

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)
{Date tmp = *this;tmp += day;return tmp;
}

2. 日期减天数

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)
{Date tmp = *this;tmp -= day;return tmp;
}

3. 两个日期相减

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

🫠这三个日期功能在日常中实际使用最频繁,因此需要保证函数功能的正确性。

第三部分: Test.cpp

#include "Date.h"void Test1()
{Date d1(2025, 8, 1);d1.Print();Date d2 = d1 + 100;d2.Print();//d1 += 10000;//d1.Print();
}void Test2()
{Date d3(2025, 8, 3);d3.Print();Date d4 = d3 - 215;d4.Print();//d3 -= 184;//d3.Print();
}void Test3()
{Date d1(2025, 8, 3);Date ret1 = d1++;ret1.Print();d1.Print();Date d2(2025, 8, 3);Date ret2 = ++d2;ret2.Print();d2.Print();
}void Test4()
{Date d1(2025, 8, 3);Date ret1 = d1--;ret1.Print();d1.Print();Date d2(2025, 8, 3);Date ret2 = --d2;ret2.Print();d2.Print();
}void Test5()
{Date d1(2025, 8, 3);Date d2(2025, 8, 4);cout << (d1 == d2) << endl;cout << (d1 != d2) << endl;
}int main()
{Test1();Test2();Test3();Test4();Test5();return 0;
}

😎Test.cpp 这部分内容是对前面函数功能的测试,大家可以自行修改。

第四部分:总结

🤗文章内有不熟悉的知识点,可以去看我写的关于运算符重载这篇文章👇:

C++基础知识点(五)- CSDN博客

💯如果这篇文章对你有用的话,请继续关注! 

欢迎大家评论区留言交流,你的关注是我最大的动力 !

http://www.lryc.cn/news/617451.html

相关文章:

  • MFC C++ 使用ODBC方式调用Oracle数据库的详细步骤
  • 重学React(五):脱围机制一
  • 金蝶云星辰:赋能企业数据管理
  • spring boot 整合redis教程
  • 带简易后台管理的米表系统 域名出售系统 自适应页面
  • 帝国理工学院团队研发:Missense3D-PTMdb—— 解析遗传变异与翻译后修饰的交互式工具
  • 计算机网络---交换机
  • 套接字技术、视频加载技术、断点续传技术
  • Horse3D引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
  • 2025 年国内可用 Docker 镜像加速器地址
  • Rust面试题及详细答案120道(19-26)-- 所有权与借用
  • 《基于Pytorch实现的声音分类 :网页解读》
  • YOLOv8 训练报错:PyTorch 2.6+ 模型加载兼容性问题解决
  • 【JavaEE】(12) 创建一个 Sring Boot 项目
  • 第二届机电一体化、机器人与控制系统国际会议(MRCS 2025)
  • 34-Hive SQL DML语法之查询数据-3
  • 2025世界机器人大会,多形态机器人开启商业化落地浪潮
  • [4.2-2] NCCL新版本的register如何实现的?
  • GAI 与 Tesla 机器人的具体联动机制
  • 记录一下通过STC的ISP软件修改stc32的EEPROM值大小
  • VoxCraft-生数科技推出的免费3D模型AI生成工具
  • uni-app app端安卓和ios如何申请麦克风权限,唤起提醒弹框
  • 设计模式笔记_结构型_组合模式
  • 5G NTN 卫星测试产品
  • 5G NR 非地面网络 (NTN) 5G、太空和统一网络
  • 用Python实现Excel转PDF并去除Spire.XLS水印
  • 深度剖析 Linux 信号:从基础概念到高级应用,全面解析其在进程管理与系统交互中的核心作用与底层运行机制
  • 电力仿真系统:技术革新与市场格局的深度解析
  • 【CV 目标检测】①——目标检测概述
  • 【Oracle】如何使用DBCA工具删除数据库?