C++【类和对象】(取地址运算符重载与实现Date类)

文章目录

  • 取地址运算符重载
    • const成员函数
    • 取地址运算符重载
  • Date类的实现
    • Date.h
    • Date.cpp
      • 1.检查日期合法性
      • 2. 构造函数/赋值运算符重载
      • 3.得到某月的天数
      • 4. Date类 +- 天数的操作
        • 4.1 日期 += 天数
        • 4.2 日期 + 天数
        • 4.3 日期 -= 天数
        • 4.4 日期 - 天数
      • 5. Date的前后置++/--
        • 5.1 前置++
        • 5.2 后置++
        • 5.3 前置--
        • 5.4 后置--
      • 6. Date类之间的比较
        • 6.1 < 操作符
        • 6.2 ==操作符
        • 6.3 <=操作符
        • 6.4 >操作符
        • 6.5 >=操作符
        • 6.6 !=操作符
      • 7.日期-日期
      • 8. Date的流插入与流提取
        • 8.1流插入函数
        • 8.2 流提取函数
    • Test.cpp
  • 结语

取地址运算符重载

const成员函数

  • 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面。
  • const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。const修饰Date类的Print成员函数,Print隐含的this指针由Date* const this变成 const Date* const this

还是拿Date类举例,如果我用const 修饰的对象来调用Print会发生报错,原因是Print隐含的this指针是Date* const this,当我用const对象来调用Print会发生权限放大。
在这里插入图片描述
但是用const修饰成员函数,就可以解决问题,因为用const修饰后Print隐含的this指针由Date* const this变成 const Date* const this,就不会出现权限放大。

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){//cout << "这是构造函数" << endl;_year = year;_month = month;_day = day;}//void Print(const Date* const this)void Print() const{cout << _year << '/' << _month << '/' << _day << endl;}private:int _year;int _month;int _day;
};

在这里插入图片描述

取地址运算符重载

取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数编译器自动生成的就可以够我们用了,不需要去显示实现。除非一些很特殊的场景,比如我们不想让别⼈取到当前类对象的地址,就可以自己实现⼀份,胡乱返回⼀个地址。

    Date* operator&(){//return nullptr;(胡乱给的地址)return this;}const Date* operator&() const{//return nullptr;(胡乱给的地址)return this;}

Date类的实现

我们在实现一个任务的时候,可以让声明与定义分离,这是一个好习惯。

Date.h

#pragma once
#include<iostream>
using namespace std;
class Date
{
public://1.检查日期的合法性bool CheckDate();//2.构造函数与赋值运算符重载Date(int year = 1, int month = 1, int day = 1);Date& operator=(const Date& d);bool LeapYear(int year){if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)){return true;}return false;}//3.得到某月天数int GetMonthDay(int year, int month){static int month_day[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };if (month == 2 && LeapYear(year)){return month_day[month] + 1;}return month_day[month];}//4. Date类 +- 天数的操作Date operator+(const int day);Date& operator+=(const int day);Date operator-(const int day);Date& operator-=(const int day);//5. Date的前后置++/--Date& operator++();Date operator++(int);Date& operator--();Date operator--(int);//6. Date类之间的比较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);void Print();//7. 日期-日期(算相差多少天)int operator-(const Date& d);//8. 日期的流插入与流提取friend ostream& operator<<(ostream& out, Date& d);friend istream& operator>>(istream& in, Date& d);private:int _year;int _month;int _day;
};

Date.cpp

实现前要包头文件

#include"Date.h"

1.检查日期合法性

	//检擦日期合法性bool Date:: CheckDate(){if (_month <= 0 || _month >= 13 || _day > GetMonthDay(_year, _month) || _day <= 0){return false;}return true;}

2. 构造函数/赋值运算符重载

构造函数

    Date::Date(int year, int month, int day){//cout << "这是构造函数" << endl;_year = year;_month = month;_day = day;while (!CheckDate()){cout << "非法日期" << endl;cout << *this;cout << "请重新输入日期" << endl;cin >> *this;}}

其实我们是不需要写拷贝构造和赋值运算符重载,因为Date类内部的成员对象并没有指向资源。
但是我们写赋值运算符重载是为了实现连续赋值。

    Date& Date::operator=(const Date&d){//如果不是自己给自己赋值if (this != &d){_year = d._year;_month = d._month;_day = d._day;}//d1 = d2 应该返回前者(因为前者是被改变的) 所以要返回*thisreturn *this;}

3.得到某月的天数

因为GetMonthDay这个函数会被频繁大量的调用,所以我们放在类里面定义(类里面的函数默认inline展开)

	//判断闰年(其实这个函数没必要写,但我为了美观就写了该函数)bool LeapYear(int year){if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)){return true;}return false;}//得到某月的天数int GetMonthDay(int year, int month){//将month_day静态化,这样就不用反复的创建数组static int month_day[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };if (month == 2 && LeapYear(year)){return month_day[month] + 1;}return month_day[month];}

4. Date类 ± 天数的操作

加减的是天数

4.1 日期 += 天数

加等使用的是进位思想,当这个月满了,向下个月借天数(同时月份也会+1)当月份大于12时,就将年份+1,同时月份到一月,直到日期为合法。

    Date& Date::operator+=(const int day){if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay(_year,_month)){int tmp = GetMonthDay(_year, _month);_day -= tmp;++_month;if (_month > 12){_month = 1;++_year;}}return *this;}
4.2 日期 + 天数

这里我们可以直接复用 日期+=天数 !

    Date Date::operator+(const int day){Date tmp(*this);tmp += day;return tmp;}
4.3 日期 -= 天数

-=与+=的实现十分类似,只不过-=使用的是退位的思想,向前一个月借天数(月份-1),当月份小于1,年份-1,月份到12月,直到日期合法

    Date& Date:: operator-=(const int day){if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){--_month;if (_month == 0){_month = 12;--_year;}int tmp = GetMonthDay(_year, _month);_day += tmp;}
4.4 日期 - 天数

和+一样,复用-=

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

5. Date的前后置++/–

前置不需要加入int形参,后置需要加入int形参。

5.1 前置++

复用+=

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

在参数位置上加一个int形参

    Date Date::operator++(int){Date tmp = *this;*this += 1;return tmp;}
5.3 前置–
    Date& Date::operator--(){*this -= 1;return *this;}
5.4 后置–
    Date Date::operator--(int){Date tmp = *this;*this -= 1;return tmp;}

6. Date类之间的比较

完成 < + == 或者 > + ==其他的比较就可以复用了。
本文实现的是 < + ==

6.1 < 操作符
    bool Date:: operator<(const Date& d){if (_year > d._year){return false;}else if (_year == d._year){if (_month >= d._month){return false;}else if (_month == d._month){if (_day >= d._day){return false;}}}return true;}
6.2 ==操作符
   bool Date::operator==(const Date& d){return _year == d._year &&_month == d._month &&_day == d._day;}
6.3 <=操作符
   bool Date::operator<=(const Date& d){return (*this < d) || (*this == d);}
6.4 >操作符
    bool Date::operator>(const Date& d){   return !(*this <= d);}
6.5 >=操作符
    bool Date::operator>=(const Date& d){return !(*this < d);}
6.6 !=操作符
    bool Date::operator!=(const Date& d){return !(*this == d);}

7.日期-日期

我们使用最简单的思路,取到区分较大和较小的日期,让较小的日期+1加到与较大的日期相等,同时记加了多少次,就得到了日期之间的天数。(cup的运行速度超级快,每秒上亿次,所以这点运算量对于cup来说轻轻松松)

    //Date-Dateint Date::operator-(const Date& d){int n = 0;int flag = 1;//假设法Date min = *this;Date max = d;if (min > max){min = d;max = *this;flag = -1;}//计算天数while (min != max){++min;++n;}return n * flag;}

8. Date的流插入与流提取

8.1流插入函数
ostream& operator<<(ostream& out, Date& d)
{cout << d._year << '/' << d._month << '/' << d._day << endl;return out;
}

注意,这里流插入和流提取都是全局函数,而非类的成员函数,其实我们在类里面也可以实现,但是会很怪。

由于成员函数的第一个参数默认是this,但运算符重载的规定是,当两个变量使用重载的运算符,会将左边的变量视为第一个参数,右边的变量视为第二个参数;这样的话,我们就不能写成cout << Date类实例化的对象,而是要写成Date类实例化的对象 << coutcin同理。

但是这样并不符合我们的习惯,所以我们设置成了全局函数,但是全局函数又有一个问题,就是Date类内部的成员变量是私有的,外部不能访问。
对此我们有以下几个方法:

  1. 将成员变量公有化(最最最不推荐的方法)
  2. 用get函数来得到成员变量
  3. 使用友元函数
  4. 放到类的内部(因参数问题不考虑)

这里我们使用的是友元函数(后面会详细讲解)。

8.2 流提取函数
istream& operator>>(istream& in, Date& d)
{cin >> d._year >> d._month >> d._day;while (!d.CheckDate()){cout << "非法日期" << endl;cout << d;cout << "请重新输入日期" << endl;cin >> d;}return in;
}

Test.cpp

#include"Date.h"void Test1()
{Date d1;Date d2(2026, 2, 28);//Date d3(2029, 9, 33);Date d3(2029, 9, 30);d1.Print();d2.Print();d3.Print();d3 = d2 = d1;d1.Print();d2.Print();d3.Print();
}void Test2()
{Date d1(2026, 2, 28);d1 += 10000;d1.Print();d1 -= 10000;d1.Print();Date d2 = d1 + 10000;d2.Print();Date d3 = d1 - 10000;d3.Print();
}void Test3()
{Date d1(2026, 2, 28);Date d2 = ++d1;d2.Print();Date d3 = d1++;d3.Print();    Date d4 = --d1;d4.Print();   Date d5 = d1--;d5.Print();
}
void Test4()
{Date d1(2024, 9, 28);Date d2(2026, 2, 28);cout << (d1 == d2) << endl;cout << (d1 != d2) << endl;cout << (d1 < d2) << endl;cout << (d1 <= d2) << endl;cout << (d1 > d2) << endl;cout << (d1 >= d2) << endl;
}void Test5()
{Date d1(2024, 9, 28);Date d2(2026, 2, 28);cout << d1 - d2 << endl;
}void Test6()
{Date d1;cin >> d1;cout << d1;
}int main()
{//Test1();//Test2();//Test3();//Test4();//Test5();Test6();return 0;
}

结语

这次的分享就到这里结束了~
最后感谢您能阅读完此片文章~
如果您认为这篇文章对你有帮助的话,可以用你们的手点一个免费的赞并收藏起来哟~
如果有任何建议或纠正欢迎在评论区留言~
也可以前往我的主页看更多好文哦(点击此处跳转到主页)。

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

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

相关文章

ORM的了解

什么是ORM&#xff1f;为什么要用ORM&#xff1f;-CSDN博客 C高级编程&#xff08;99&#xff09;面向资源的设计思想&#xff08;ORM&#xff09;_c orm-CSDN博客 ORM:Object-Relational-Mapping 对象关系映射 -------------------------- 我想对数据库中的表A进行增删改…

天龙八部怀旧单机微改人面桃花+安装教程+GM工具+虚拟机一键端

今天给大家带来一款单机游戏的架设&#xff1a;天龙八部怀旧单机微改人面桃花。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xf…

【Mybatis篇】动态SQL的详细带练

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 文章目录 &#x1f3af;一.动态SQL简单介绍 &#x1f6a6;动态S…

【深度】为GPT-5而生的「草莓」模型!从快思考—慢思考到Self-play RL的强化学习框架

原创 超 超的闲思世界 2024年09月11日 19:17 北京 9月11日消息&#xff0c;据外媒The Information昨晚报道&#xff0c;OpenAI的新模型「草莓」&#xff08;Strawberry&#xff09;&#xff0c;将在未来两周内作为ChatGPT服务的一部分发布。 「草莓」项目是OpenAI盛传已久的…

全网最全软件测试面试题(含答案解析+文档)

一、软件测试基础面试题 1、阐述软件生命周期都有哪些阶段? 常见的软件生命周期模型有哪些? 软件生命周期是指一个计算机软件从功能确定设计&#xff0c;到开发成功投入使用&#xff0c;并在使用中不断地修改、增补和完善&#xff0c;直到停止该软件的使用的全过程(从酝酿到…

YOLO V8半自动标注工具设计

前提&#xff1a; 对于某些边界不明确的小目标&#xff0c;要是目标由比较多的话&#xff0c;标注起来就会非常麻烦。 如何利用已有训练模型&#xff0c;生成框&#xff0c;进行预标注。再通过调节预标注框的方式&#xff0c;提高标注的效率。 1 通过预先训练的模型生成yolo 格…

一文上手SpringSecurity【七】

之前我们在测试的时候,都是使用的字符串充当用户名称和密码,本篇将其换成MySQL数据库. 一、替换为真实的MySQL 1.1 引入依赖 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</v…

Jenkins Pipeline 中通过勾选参数来控制是否构建 Docker 镜像

1.定义参数&#xff1a; 使用 booleanParam 定义一个布尔参数&#xff0c;示例如下 booleanParam(name: BUILD_DOCKER, description: 是否构建Docker镜像, defaultValue: false)2.使用参数&#xff1a; 在 stage 中&#xff0c;根据参数的值决定构建方式&#xff1a; stage(编…

python基础库

文章目录 1.研究目的2.platform库介绍3.代码4.结果展示 1.研究目的 最近项目中需要利用python获取计算机硬件的一些基本信息,查阅资料,.于是写下这篇简短的博客,有问题烦请提出,谢谢-_- 2.platform库介绍 platform 库是 Python 的一个内置库&#xff0c;可以让我们轻松地获取…

spring boot 项目中redis的使用,key=value值 如何用命令行来查询并设置值。

1、有一个老项目&#xff0c;用到了网易云信&#xff0c;然后这里面有一个AppKey&#xff0c;然后调用的时候要在header中加入这些标识&#xff0c;进行与服务器进行交互。 2、开发将其存在了redis中&#xff0c;一开始的时候&#xff0c;我们测试用的老的key&#xff0c;然后提…

ValueError: Out of range float values are not JSON compliant

可能原因一 可能原因二 数据里面有NaN

算法: 滑动窗口题目练习

文章目录 滑动窗口长度最小的子数组无重复字符的最长子串最大连续1个个数 III将x减到0的最小操作数水果成篮找到字符串中所有字母异位词串联所有单词的子串最小覆盖子串 总结 滑动窗口 长度最小的子数组 做这道题时,脑子里大概有个印象,知道要用滑动窗口,但是对于滑动窗口为什…

2016年国赛高教杯数学建模D题风电场运行状况分析及优化解题全过程文档及程序

2016年国赛高教杯数学建模 D题风电场运行状况分析及优化 风能是一种最具活力的可再生能源&#xff0c;风力发电是风能最主要的应用形式。我国某风电场已先后进行了一、二期建设&#xff0c;现有风机124台&#xff0c;总装机容量约20万千瓦。请建立数学模型&#xff0c;解决以下…

探索私有化聊天软件:即时通讯与音视频技术的结合

在数字化转型的浪潮中&#xff0c;企业对于高效、安全、定制化的通讯解决方案的需求日益迫切。鲸信&#xff0c;作为音视频通信技术的佼佼者&#xff0c;凭借其强大的即时通讯与音视频SDK&#xff08;软件开发工具包&#xff09;结合能力&#xff0c;为企业量身打造了私有化聊天…

MySQL Mail服务器集成:如何配置发送邮件?

MySQL Mail插件使用指南&#xff1f;怎么优化 MySQL发邮件性能&#xff1f; MySQL Mail服务器的集成&#xff0c;使得数据库可以直接触发邮件发送&#xff0c;极大地简化了应用架构。AokSend将详细介绍如何配置MySQL Mail服务器&#xff0c;以实现邮件发送功能。 MySQL Mail&…

【YashanDB知识库】如何配置jdbc驱动使getDatabaseProductName()返回Oracle

本文转自YashanDB官网&#xff0c;具体内容请见https://www.yashandb.com/newsinfo/7352676.html?templateId1718516 问题现象 某些三方件&#xff0c;例如 工作流引擎activiti&#xff0c;暂未适配yashandb&#xff0c;使用中会出现如下异常&#xff1a; 问题的风险及影响 …

【STM32】江科大STM32笔记汇总(已完结)

STM32江科大笔记汇总 STM32学习笔记课程简介(01)STM32简介(02)软件安装(03)新建工程(04)GPIO输出(05)LED闪烁& LED流水灯& 蜂鸣器(06)GPIO输入(07)按键控制LED 光敏传感器控制蜂鸣器(08)OLED调试工具(09)OLED显示屏(10)EXTI外部中断(11)对射式红外传感器计次 旋转编码器…

K8S服务发布

一 、服务发布方式对比 二者主要区别在于&#xff1a; 1、部署复杂性&#xff1a;传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等&#xff0c;过程相对复 杂且容易出错。相比之下&#xff0c;Kubernetes服务发布方式 通过使用容器编排和自动化部署工…

QT----Creater14.0,qt5.15无法启动调试,Launching GDB Debugger报红

问题描述 使用QT Creater 14.0 和qt5.15,无法启动调试也没有报错,加载debugger报红 相关文件都有 解决方案 尝试重装QT,更换版本5.15.2,下载到文件夹,shift鼠标右键打开powershell输入 .\qt-online-installer-windows-x64-4.8.0.exe --mirror http://mirrors.ustc.edu.cn…

解决fatal: unable to access ‘https://........git/‘: Recv failure: Operation time

目录 前言 解决方法一 解决方法二 解决方法三 解决方法四 总结 前言 在使用 Git 进行代码拉取时&#xff0c;可能会遇到连接超时的问题&#xff0c;特别是在某些网络环境下&#xff0c;例如公司网络或防火墙严格的环境中。这种情况下&#xff0c;Git 无法访问远程仓…