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

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;
}

结语

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

相关文章:

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

文章目录 取地址运算符重载const成员函数取地址运算符重载 Date类的实现Date.hDate.cpp1.检查日期合法性2. 构造函数/赋值运算符重载3.得到某月的天数4. Date类 - 天数的操作4.1 日期 天数4.2 日期 天数4.3 日期 - 天数4.4 日期 - 天数 5. Date的前后置/--5.1 前置5.2 后置5.…...

oracle 数据库中的异常和游标管理

异常和游标管理 游标&#xff1a; 用来查询数据库&#xff0c;获取记录集合&#xff08;结果集&#xff09;的指针&#xff0c;可以让开发者一次访问一行结果集&#xff0c;在每条结果集上作操作。 分类&#xff1a; 静态游标&#xff1a; 分为显式游标和隐式游标。 REF游标&…...

关于python 日志设定为INFO 但是DEBUG仍旧写入的问题

问题&#xff1a;将logging设定为了INFO级别&#xff0c;但是在打印的时候发现jieba包中的DEBUG级别的信息还是出现了。 原因&#xff1a;在我引用的包中&#xff0c;一些python文件也使用了logging&#xff0c;我设定的INFO级别只能设定我当前使用的文件&#xff0c;而调用的包…...

TypeScript 语法基础 第一部分 类型

【视频链接】尚硅谷TypeScript教程&#xff08;李立超老师TS新课&#xff09; TypeScript TypeScript 语法基础 第二部分 类、接口、泛型1. 类型1.1 | 联合类型1.2 字面量类型1.3 any 任意类型1.4 unkown 类型1.5 as 类型断言1.6 object 对象类型1.7 { } 对象类型1.8 &#xff…...

GO Serial 学习与使用

文章目录 主要特性安装基本用法配置选项错误处理其他功能 github.com/goburrow/serial 是一个 Go 包&#xff0c;提供了一种简单的方式来与串口进行交互。以下是该包的主要特性和用法的简要概述&#xff1a; 主要特性 跨平台支持&#xff1a;支持 Windows、macOS 和 Linux。简…...

安卓app开发系列之-常用工具与库

✨ 关于我 ✨ &#x1f468;‍&#x1f4bb; Hi there! 我是 [Jamson]&#xff0c;一名热爱编程与技术的狂热者&#xff0c;致力于前后端的全栈独立软件系统开发。通过不断学习和实践&#xff0c;我希望将知识分享给更多的朋友们&#xff0c;和大家一起成长。 &#x1f4a1; &…...

视频汇聚EasyCVR视频监控平台调取接口提示“认证过期”是什么原因?

视频汇聚EasyCVR视频监控平台&#xff0c;作为一款智能视频监控综合管理平台&#xff0c;凭借其强大的视频融合汇聚能力和灵活的视频能力&#xff0c;在各行各业的应用中发挥着越来越重要的作用。EasyCVR平台具备强大的拓展性和灵活性&#xff0c;支持多种视频流的外部分发&…...

uniapp视频禁止用户推拽进度条并保留进度条显示的解决方法——方案二

在uniapp项目中&#xff0c;使用<video>组件播放视频非常方便。默认情况下&#xff0c;视频组件会显示进度条&#xff0c;用户可以随意拖动进度条来控制视频播放进度。然而&#xff0c;在某些特定场景&#xff0c;如在线教育、广告宣传等&#xff0c;我们希望禁止用户拖动…...

mysql复合查询 -- 多表查询(介绍,笛卡尔积,使用),自连接(介绍,使用)

目录 多表查询 介绍 使用 表数据 显示雇员名,雇员工资,以及所在部门名 显示部门号为10的部门名,员工名,工资 自连接 介绍 场景 表数据 题目 子查询 自连接 多表查询 介绍 实际开发中往往数据来自不同的表&#xff0c;所以需要多表查询 语法: from 表1,表2 (笛卡…...

【个人笔记】数据一致性的解决方案

保证数据一致性&#xff1a;指保证redis里的数据和mysql的数据是一致的&#xff0c;不能说mysql更新了&#xff0c;但redis里面的还是旧的数据&#xff0c;反之亦然 先说结论&#xff1a;增删改的时候&#xff0c;把Redis中的缓存删了 为什么不先更新数据库&#xff0c;再更新…...

【WPF】多屏幕展示

使用环境为.Net Framework&#xff0c;如果有.Net 6的解决方案&#xff0c;欢迎交流。 话不多说&#xff0c;先上代码&#xff01; /// <summary>/// Window窗口展示设置/// </summary>/// <param name"monitor"></param>/// <param nam…...

vue admin 若依框架 解决无权限时进入死循环的问题 auths

核心原因&#xff1a; if (auths && auths.length > 0) { // like12 find bug,数组为空[]时依然会进入死循环 原来为&#xff1a;if (auths) // 获取用户信息getInfo({ commit, state }) {return new Promise((resolve, reject) > {getInfo(state.token).then(…...

kubernetes存储入门(kubernetes)

实验环境依旧是三个节点拉取镜像&#xff0c;然后在master节点拉取资源清单&#xff1a; 然后同步会话&#xff0c;导入镜像&#xff1b; 存储入门 ConfigMap volume卷--》volumemount&#xff08;挂载卷&#xff09; Glusterfs NFS ISCSI HostPath ConfigMap Secret E…...

局部代理有什么好处?为什么不使用全局代理?

1. 什么是局部代理与全局代理&#xff1f; 局部代理&#xff1a;局部代理只会对特定应用程序或特定的网络流量进行代理&#xff0c;而不会影响其他网络流量。例如&#xff0c;你可以设置浏览器使用代理&#xff0c;而其他应用程序如邮件客户端或游戏仍然使用本地网络连接。 全…...

ssm模糊知识点整合

一、参数绑定常用注解 RequestParam&#xff1a;用于将请求参数绑定到你的方法参数上。 PathVariable&#xff1a;用于将路径变量绑定到你的方法参数上。 RequestBody&#xff1a;用于将请求主体绑定到你的方法参数上&#xff0c;通常用于绑定POST请求的JSON或XML数据。 Req…...

2、Spring Boot 3.x 集成 Feign

一、前言 本篇主要是围绕着两个点&#xff0c;1、集成 Feign&#xff0c;2、分离feign接口层&#xff0c;独立服务&#xff1b; 还有一点就是上篇文章的服务 iot-channel、system-server 服务名称调整成为了 chain-iot-channel、chain-system二、搭建 chain-common 服务 pom.…...

深度学习-图像处理篇-5ResNet和ResNeXt

解决问题&#xff1a; 梯度消失或梯度爆炸 退化问题(degradation problem) 迁移学习 ResNeXt...

类的关联、依赖、聚合和组合关系的思考(一)

最近在看《设计模式》这本书&#xff0c;发现对类之间的关系还没搞的很明白&#xff0c;而类之间的关系对读书、阅读代码和代码设计都非常重要&#xff0c;因此边看书边查阅了一些资料&#xff0c;感觉有些理解了。下面是我的一些思考&#xff0c;分享一下。 查阅了很多博客&a…...

云舟观测:集成开源Grafana Faro构建前端页面性能监控平台

在当今互联网时代&#xff0c;面对纷乱繁杂的网上资源&#xff0c;用户的耐心和注意力是极为宝贵的资源&#xff0c;当用户访问一个网站或应用时&#xff0c;他们期望的是快速且无缝的体验&#xff0c;任何加载延迟或功能故障都可能导致用户流失&#xff0c;影响品牌体验。因此…...

c# 子类继承父类接口问题

在C#中&#xff0c;子类并不直接“继承”父类继承的接口&#xff0c;但子类的确会继承父类对接口的实现&#xff08;如果父类实现了该接口&#xff09;。这里有一些关键的概念需要澄清&#xff1a; 接口继承&#xff1a;当一个类实现了某个接口时&#xff0c;它必须实现接口中…...

Vue 中自定义指令的探索与实践

文章目录 一、Vue 自定义指令简介二、基本语法三、指令的值四、封装v-loading指令五、总结 在 Vue 开发中&#xff0c;自定义指令为我们提供了一种强大的方式来操作 DOM 元素&#xff0c;实现特定的交互效果和功能增强。本文将深入探讨 Vue 中自定义指令的基本语法、指令的值的…...

Vue3通过$emit实现子向父传递数据

引言 子组件通过$emit触发事件&#xff0c;并传递数据&#xff0c;父组件在使用子组件时就可以绑定子组件事件&#xff0c;在事件处理函数中拿到子组件传来的数据 子组件传递数据 函数声明&#xff1a;$emit(事件名, 传递的数据 . . .) 子组件传递的数据会依次传递给父组件的…...

代码随想录算法训练营第十四天|递归 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度

226.翻转二叉树 翻转一棵二叉树。 思路&#xff1a; 在这里需要注意的是&#xff0c;在递归的时候唯独中序遍历是不可用的&#xff0c;这是因为先对左子树进行了反转&#xff0c;又对自身进行了反转&#xff0c;对自身反转后原本的左子树变成了右子树&#xff0c;如果此时又轮…...

Spark 任务与 Spark Streaming 任务的差异详解

Spark 任务与 Spark Streaming 任务的主要差异源自于两者的应用场景不同&#xff1a;Spark 主要处理静态的大数据集&#xff0c;而 Spark Streaming 处理的是实时流数据。这些差异体现在任务的调度、执行、容错、数据处理模式等方面。 接下来&#xff0c;我们将从底层原理和源…...

Git提示信息 Pulling is not possible because you have unmerged files.

git [fatal] hint: Pulling is not possible because you have unmerged files.hint: Fix them up in the … error: Pulling is not possible because you have unmerged files. 错误:无法提取&#xff0c;因为您有未合并的文件。 hint: Fix them up in the work tree, and t…...

python编程开发“人机猜拳”游戏

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…...

丹摩智算平台部署 Llama 3.1:实践与体验

文章目录 前言部署前的准备创建实例 部署与配置 Llama 3.1使用心得总结 前言 在最近的开发工作中&#xff0c;我有机会体验了丹摩智算平台&#xff0c;部署并使用了 Llama 3.1 模型。在人工智能和大模型领域&#xff0c;Meta 推出的 Llama 3.1 已经成为了目前最受瞩目的开源模…...

SpringCloud 2023各依赖版本选择、核心功能与组件、创建项目(注意事项、依赖)

目录 1. 各依赖版本选择2. 核心功能与组件3. 创建项目3.1 注意事项3.2 依赖 1. 各依赖版本选择 SpringCloud: 2023.0.1SpringBoot: 3.2.4。参考Spring Cloud Train Reference Documentation选择版本 SpringCloud Alibaba: 2023.0.1.0*: 参考Spring Cloud Alibaba选择版本。同时…...

串行化执行、并行化执行

文章目录 1、串行化执行2、并行化测试&#xff08;多线程环境&#xff09;3、任务的执行是异步的&#xff0c;但主程序的继续执行是同步的 可以将多个任务编排为并行和串行化执行。 也可以处理编排的多个任务的异常&#xff0c;也可以返回兜底数据。 1、串行化执行 顺序执行、…...

二叉搜索树(c++版)

前言 在前面我们介绍过二叉树这个数据结构&#xff0c;今天我们更进一步来介绍二叉树的一种在实现中运用的场景——二叉搜索树。二叉搜索树顾名思义其在“搜索”这个场景下有不俗的表现&#xff0c;之所以会这样是因为它在二叉树的基础上添加了一些属性。下面我们就来简单的介…...