代码总览与总结

// 实现一个完善的日期类
class Date
{
public:int GetMonthDay(int year, int month){int monthDays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };// 闰年2月if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))return 29;return monthDays[month];}Date(int year = 0, int month = 1, int day = 1){// 如果日期合法if (year >= 0 && month >= 1 && month <= 12 && day >= 1 && day <= GetMonthDay(year,month)){_year = year;_month = month;_day = day;}else{cout << "非法日期" << endl;}}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d){return _year == d._year&& _month == d._month&& _day == d._day;}bool operator<(const Date& d){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;return false;}bool operator<=(const Date& d){// 函数原型为 operator<=(Date* this, const Date& d)// 函数调用时相当于传参 operator<=(&d1, d2)// 此处 *this = *(&d1),即d1return *this < d || *this == d;// 所以上面的代码等价于// return d1 < d2 || d1 == d2;}// 通过 *this ,我们可以很轻松实现代码的复用// 代码的复用有很多好处,当未来加入什么“时分秒”时不需要修改全部函数// 只需要修改一开始的少数函数就可以达成修改全部函数的目的// 复用是高内聚,写代码的提倡的就是低耦合高内聚bool operator>(const Date& d){return !(*this <= d);}bool operator>=(const Date& d){return !(*this < d);}bool operator!=(const Date& d){return !(*this == d);}// +//Date operator+(int day)//{//        Date ret(*this);        // 拷贝构造一个ret//        ret._day += day;//        while (ret._day > GetMonthDay(ret._year, ret._month))//        {//                // 日期大于天数上限,往月进位//                ret._day -= GetMonthDay(ret._year, ret._month);//                ret._month++;//                // 检查月份合法性//                if (ret._month > 12)//                {//                        ret._month = 1;//                        ret._year++;//                }//        }//        return ret;//}// +// 复用实现Date operator+(int day){Date ret(*this);        // 拷贝构造一个retret += day;                        // ret.operator+=(day)return ret;}// +=// 类对象本身在函数外,所以可以传引用返回Date& operator+=(int day){if (day < 0){return *this -= -day;}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_year++;_month = 1;}}return *this;}// -/*Date operator-(int day){Date ret(*this);ret._day -= day;while (ret._day <= 0){ret._month--;if (ret._month <= 0){ret._year--;ret._month = 12;}ret._day += GetMonthDay(ret._year, ret._month);}return ret;}*/// -// 复用实现Date operator-(int day){Date ret(*this);ret -= day;                        // operator-=(day)return ret;}// -=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& operator++(){*this += 1;return *this;}// ++(后置++)// 为了构成函数重载,函数参数加了一个int,但实际不用传参数// 这个int仅仅是编译器为了构成函数重载加上的Date operator++(int){Date tmp(*this);*this += 1;return tmp;}// --(前置--)Date& operator--(){*this -= 1;return *this;}//--(后置--)// 为了构成函数重载,函数参数加了一个int,但实际不用传参数// 这个int仅仅是编译器为了构成函数重载加上的Date operator--(int){Date tmp(*this);*this -= 1;return tmp;}// d1 - d2int operator-(const Date& d){int flag = 1;Date max = *this;        // 拷贝构造Date min = d;if (*this < d){max = d;                // operator=min = *this;flag = -1;}int n = 0;while (min != max){++min;        // 参考前置++与后置++的实现,自定义类型能用前置++就不要用后置++n;}return n * flag;}// 赋值运算符重载// d3 = d1// 运算符的重载是为了让自定义类性可以像内置类型一样去使用运算符Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};

1. 核心功能

  • 日期计算:加减天数、递增递减(前置/后置)

  • 日期比较:全部6种关系运算符(==, !=, <, <=, >, >=)

  • 日期差值:计算两个日期之间相差的天数

    2. 设计亮点

    • 高内聚低耦合:通过运算符复用来减少代码冗余(例如,用 ==< 实现其他所有比较运算符;用 += 实现 +)。

    • 鲁棒性:构造函数进行了日期合法性检查;加减操作处理了负数和跨年月的情况。

    • 效率考虑:在日期差值计算中,使用小日期自增到大日期的方式,简单可靠。

      3. 关键技术点

      • 闰年的判断与二月份天数的动态获取。

      • 前置与后置自增/自减运算符的重载区分。

      • 赋值运算符的自我赋值检查。

      • 对于 +=-=,处理了传入负数的特殊情况,增强了接口的健壮性。


        分段代码讲解

        1. 辅助函数与构造函数

        int GetMonthDay(int year, int month)
        {int monthDays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };// 闰年2月if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))return 29;return monthDays[month];
        }Date(int year = 0, int month = 1, int day = 1)
        {// 检查日期合法性if (year >= 0 && month >= 1 && month <= 12 && day >= 1 && day <= GetMonthDay(year,month)){_year = year;_month = month;_day = day;}else{cout << "非法日期" << endl;// 注意:这里最好抛出一个异常,或者将日期设为一个确定的合法状态(如1970-1-1),而不是仅仅打印。}
        }
        • GetMonthDay: 根据年份和月份返回对应的天数,核心是处理闰年二月的特殊情况。

        • 构造函数: 提供了全缺省参数。首先检查传入的日期是否合法,合法则初始化,否则输出错误信息。**建议改进**:在非法日期时进行错误处理(如抛出异常),而不仅仅是打印。

          2. 拷贝构造与基本比较运算符

          Date(const Date& d)
          {_year = d._year;_month = d._month;_day = d._day;
          }bool operator==(const Date& d)
          {return _year == d._year&& _month == d._month&& _day == d._day;
          }bool operator<(const Date& d)
          {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;return false;
          }
          • 拷贝构造函数: 进行深拷贝(虽然这里都是int,但习惯上称为深拷贝)。

          • operator==: 严格比较年、月、日是否全部相等。

          • operator<: 实现了日期的字典序比较,是其他所有比较运算符的基石。

            3. 复用实现的比较运算符

            bool operator<=(const Date& d)
            {return *this < d || *this == d;
            }bool operator>(const Date& d)
            {return !(*this <= d);
            }bool operator>=(const Date& d)
            {return !(*this < d);
            }bool operator!=(const Date& d)
            {return !(*this == d);
            }
            • 复用思想:这是代码最大的亮点。只需要实现 ==<,其余四个运算符都可以通过逻辑组合轻松实现。这使得代码维护性极高,如需修改比较逻辑,只需改动 ==< 即可。

              4. 复合赋值运算符(+=, -=)

              Date& operator+=(int day)
              {if (day < 0) // 处理负数情况:加负天数等于减正天数{return *this -= -day;}_day += day;while (_day > GetMonthDay(_year, _month)) // 当天数溢出时循环调整{_day -= GetMonthDay(_year, _month);_month++;if (_month > 12) // 月份溢出,进年{_year++;_month = 1;}}return *this; // 返回自身的引用,以支持连续赋值(如 d1 += 5 += 10;)
              }Date& operator-=(int day)
              {if (day < 0) // 处理负数情况:减负天数等于加正天数{return *this += -day;}_day -= day;while (_day <= 0) // 当天数变为0或负数时,需要借位{_month--;if (_month <= 0) // 月份借完,向年借{_year--;_month = 12;}_day += GetMonthDay(_year, _month); // 借来一个月的天数加到当前天数上}return *this;
              }
              • 核心算法:这两个函数是日期计算的核心。+= 通过循环进位,-= 通过循环借位,正确处理了跨月、跨年的复杂情况。

              • 接口健壮性:处理了传入负数的边界情况,使接口更友好。

              • 返回值:返回引用 (Date&),支持链式操作(如 d1 += 10 -= 5;),这是符合内置类型行为的标准做法。

                5. 算术运算符(+, -)与递增递减(++, --)

                // 复用 += 实现 +
                Date operator+(int day)
                {Date ret(*this); // 创建当前对象的一个副本ret += day;      // 对副本进行操作return ret;      // 返回副本的结果
                }// 复用 -= 实现 -
                Date operator-(int day)
                {Date ret(*this);ret -= day;return ret;
                }// 前置++:返回自增后的自身
                Date& operator++()
                {*this += 1;return *this;
                }// 后置++:返回自增前的值(副本)
                Date operator++(int)
                {Date tmp(*this); // 保存原来的值*this += 1;      // 自身增加return tmp;      // 返回原来的值
                }// 前置--和后置--的实现逻辑与++完全相同
                Date& operator--()
                {*this -= 1;return *this;
                }Date operator--(int)
                {Date tmp(*this);*this -= 1;return tmp;
                }
                • 复用思想+- 运算符通过复用 +=-= 实现,避免了重复的进位/借位逻辑。

                • 前后置区分

                  • 前置:先计算,后返回自身的引用 (Date&)。

                  • 后置:使用 int 参数作为占位符以区分重载。先保存原状态,再计算,最后返回原状态的副本 (Date)。

                  6. 日期差值运算符(-)

                  int operator-(const Date& d)
                  {int flag = 1;Date max = *this;Date min = d;if (*this < d) // 确定大小关系,保证max是较大的日期{max = d;min = *this;flag = -1; // 如果this < d,结果应为负数}int n = 0;while (min != max) // 让小日期不断自增,直到等于大日期{++min; // 使用前置++,效率更高++n;}return n * flag; // 返回带符号的天数差
                  }
                  • 算法:采用朴素的“计数”方法,让小日期一天天加到大日期,计数器的值就是差值。方法简单正确,但对于相差很远的日子效率较低(可采用计算绝对日期数再相减的优化算法)。

                  • 符号处理:通过 flag 变量控制结果的符号,使 d1 - d2 的结果与预期一致。

                    7. 赋值运算符与打印函数

                    Date& operator=(const Date& d)
                    {if (this != &d) // 防止自我赋值(如 d1 = d1;){_year = d._year;_month = d._month;_day = d._day;}return *this; // 返回自身引用,支持链式赋值(d1 = d2 = d3;)
                    }void Print()
                    {cout << _year << "-" << _month << "-" << _day << endl;
                    }
                    • 赋值运算符:是拷贝构造的伴侣。注意**自我赋值检查** (if (this != &d)),这是一个重要的安全措施。

                    • Print函数:一个简单的格式化输出功能。

                      总结

                      这个 Date 类清晰地展示了:

                      1. 如何为自定义类型重载运算符,使其行为与内置类型一致。

                      2. 代码复用的强大威力,极大地减少了代码量和维护成本。

                      3. 边界条件处理的重要性(如闰年、日期合法性、负数操作、自我赋值等)。

                        可以进行的改进点

                        • 构造函数在遇到非法日期时,可以抛出异常 (std::invalid_argument) 而不是仅输出信息。

                        • operator- (计算差值) 的算法可以优化为计算每个日期相对于某个固定日期(如0000-01-01)的天数,然后相减,以提升效率。

                        • 可以添加 const 成员函数,如 void Print() constbool operator<(const Date& d) const,表示这些函数不会修改对象状态,可以在常量对象上调用。

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

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

                        相关文章

                        零基础json入门教程(基于vscode的json配置文件)

                        一、什么是 JSON&#xff1f;—— 最核心的概念JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;长得像键值对的集合&#xff0c;用途是存储和传递数据。在 VS Code 中&#xff0c;它常被用来写配置文件&#xff08;比如调试配置…

                        深入对比分析SpringCloud和Dubbo两大微服务框架的核心架构与特性。

                        1 微服务架构演进与核心概念1.1 微服务架构的本质微服务架构是一种将单一应用程序划分为一组小型服务的方法&#xff0c;每个服务运行在自己的进程中&#xff0c;服务之间通过轻量级的通信机制进行协作。这些服务围绕业务能力构建&#xff0c;并能够独立部署到生产环境中。微服…

                        鸿蒙ArkTS 核心篇-14-条件表达式(三目运算符)

                        目录 根据逻辑条件结果&#xff0c;执行不同的表达式&#xff0c;得到不同结果 DevEco Studio代码实战 ctrl s 日志输出 总结 根据逻辑条件结果&#xff0c;执行不同的表达式&#xff0c;得到不同结果 DevEco Studio代码实战 let num1: number 100 let num2: number 20l…

                        CDH集成LDAP进行身份验证

                        前言&#xff1a;在内网环境中部署LDAP并在CDH的hive和impala中集成&#xff0c;其中配置的端口&#xff0c;镜像名&#xff0c;密码等需要根据自己情况进行更改 1、镜像下载 在有网络的服务器上下载镜像或直接下载&#xff0c;这里需要自行配置下docker镜像下载地址 # 下载…

                        并发编程:Java中的多线程与线程池!

                        全文目录&#xff1a;开篇语线程的基础概念线程生命周期线程调度线程安全线程池&#xff1a;Executor框架、线程池的管理与调优Executor框架线程池的管理与调优并发工具类&#xff1a;ReentrantLock、CountDownLatch、CyclicBarrier等ReentrantLockCountDownLatchCyclicBarrier…

                        语义分割一站式到底怎么玩?

                        语义分割模型&#xff0c;复现或改进、对比实验&#xff0c;&#xff0c;欢迎交流&#xff0c;完爆各种详细需求1、可以接以下语义分割模型dai做 DeepLabV3、PSPnet、HRnet、Segformer、Unet、u2net、cenet、erfnet、hcanet、hiformer、uiunet、nnunet、saunet、unext、dscnet、…

                        由于不对称GND过孔配置,差分信号过孔上的差模到共模转换

                        本文研究了靠近高速差分信号过孔的接地过孔的影响以及由此产生的差模到共模的转换。该工作显示了接地 &#xff08;GND&#xff09; 过孔和差分信号之间距离的影响 &#xff08;Diff. SIG.&#xff09;;GND过孔不对称配置的影响;介电厚度和平面之间跃迁次数的影响。 印刷电路板…

                        Axios 实例配置指南

                        今天分享一段 Axios 实例配置的代码&#xff0c;用于 Web Front - End 项目的构建。 一、为什么使用 Axios 在前端项目中&#xff0c;与后端进行数据交互是必不可少的。Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;它提供了简洁的 API 和强大的功能&#xff0c;能够方…

                        分分合合,门模块方案又兴起了

                        文章目录前言1.方案概述1.1 功能需求1.2 框图2.供电和通信2.1 理想二极管控制器2.2 SBC2.3 高边开关3.门模块PCBA3.1 后视镜3.2 车窗和电动门4.车锁控制PCBA5.氛围灯PCBA6.未来趋势前言 最近接触了一些之前做门锁、门控、BCM的客户&#xff0c;发现他们或多或少都在做一些门模…

                        AWD相关知识

                        AWD AWD&#xff1a;Attack With Defence&#xff0c;即攻防对抗&#xff0c;比赛中每个队伍维护多台服务器&#xff08;一般两三台&#xff0c;视小组参赛人数而定&#xff09;&#xff0c;服务器中存在多个漏洞&#xff08;web层、系统层、中间件层等&#xff09;&#xff0c…

                        基于CNN(卷积神经网络)的门牌号识别

                        1、官网下载SVHN数据集svhn是数据集&#xff0c;Dataset2、HOG特征3、支持向量机 SVM(Support Vector Machine&#xff0c;SVM) 分类器4、cv2需要导入 pip install opencv-python5、HOG特征提取5.1 伽马校正归一化预补偿反归一化无伽马校正有伽马校正5.2 灰度化5.3 图像梯度计…

                        使用LLAMA_cpp_python进行qwen2.5-vl-7b-instruct进行推理

                        目标&#xff1a;使用python的llama_cpp运行qwen2.5vl模型实现提交图片和文本回答文本效果 遇到的问题&#xff1a; 和提交信息的判断关键点llama.cpp 作为一个用 C/C 编写的轻量级大语言模型推理框架&#xff0c;让你能在各种硬件上高效运行模型。它通过降低部署和运行大模型的…

                        PDF,HTML,md格式文件在线查看工具

                        VUE3 实现了 PDF,HTML,md格式文件在线查看工具 在线体验地址: http://114.55.230.54/ 实现了一款漂亮的PDF,HTML,md格式文件在线查看网页工具 1、PDF预览1.1 实现代码 <script setup> import { ref, watch, computed } from vue// 状态管理 const files ref([]) // 存储…

                        CPP学习之map和set

                        1. 关联式容器 在之前博客中我们提到过序列式容器&#xff1a;vector, list, deque, forward_list等&#xff0c;其底层都是线性数据结构。 关联式容器存储的是键值对–<key, value>&#xff0c;与序列式容器仅存储值–key不一样&#xff0c;在数据检索时比序列式容器效…

                        深入理解C++中的移动赋值与拷贝赋值函数——兼论移动构造函数及其实际应用场景

                        技术博客&#xff1a;深入理解C中的移动赋值与拷贝赋值函数——兼论移动构造函数及其实际应用场景引言在C编程中&#xff0c;对象的赋值和构造操作是常见的需求。随着C11标准的引入&#xff0c;移动语义&#xff08;Move Semantics&#xff09;成为提升程序性能的重要手段之一。…

                        免费在线图片合成视频工具 ,完全免费

                        免费在线图片合成视频工具 &#xff0c;完全免费 免费在线图片合成视频工具是一个完全免费的图片生成视频网站、图片和音乐合成视频网站。 它完全免费&#xff0c;无需注册登录&#xff0c;可以轻松将多张图片转换为视频&#xff0c;支持 jpeg 、png 、webp 格式图片&#xf…

                        金仓数据库 V9 体验测评:AI 时代国产数据库 “融合” 架构的真实观察

                        【非广告声明】本文为本人基于金仓数据库 V9 的真实部署测试与技术拆解&#xff0c;无任何商业合作背景&#xff0c;未接受品牌方任何形式的推广委托或费用支持。写作核心是分享国产数据库在 “融合架构”“AI 赋能”“平滑迁移” 等关键场景下的实际使用体验 —— 包括技术细节…

                        EE进阶1:Maven和SpringBoot基本介绍

                        Maven什么是mavenMaven简单的理解就是一个项目管理工具&#xff0c;使用pom.xml文件进行管理和获取.jar包&#xff0c;而不用手动进行添加.jar包。创建maven项目以及使用Maven的功能非常多&#xff0c;这里主要理解Maven的项目创建和依赖管理。项目创建&#xff1a;maven本身是…

                        【系统架构设计(三)】系统工程与信息系统基础下:企业信息化与电子商务-数字化转型的核心驱动力

                        文章目录一、信息化的基本概念1、 信息化的定义与目的2、 信息化涉及的三大创新3、信息化需求的三个层次二、企业信息化六大方法体系三、信息系统战略规划方法1、 战略规划方法的演进2、 关键成功因素法&#xff08;CSF&#xff09;3、 战略集合转化法&#xff08;SST&#xff…

                        分布式2PC理论

                        目录 什么是分布式 2PC&#xff08;Two-Phase Commit&#xff09; 2PC 的工作原理 2PC 的优缺点 为什么 2PC 不完全可靠&#xff1f; 超时问题 协调者故障 什么是分布式 2PC&#xff08;Two-Phase Commit&#xff09; 定义 2PC 是一种原子提交协议&#xff0c;用…