类和对象(中下)彻底搞懂赋值/取地址运算符重载和日期类实战
这里紧跟着我上一期博客C类和对象中上构造函数·析构函数·拷贝构造-CSDN博客去进行讲解。一.赋值运算符重载1.运算符重载本质为函数注意我们主要讲解的是赋值运算符重载这个默认成员函数而运算符重载是其实现方法要先进行学习。• 在C语言中运算符只能用来运算内置类型因为编译器会直接将运算符转换成对应的指令。现在C中推出了运算符重载其允许我们通过运算符重载的方式指定新的含义。C规定类类型对象使用运算符时必须转换成对应的运算符重载函数若没有对应的运算符重载则会编译报错。• 运算符重载是有特殊名字的函数其名字由operator和后面要定义的运算符共同构成。和其他函数一样它也具有返回类型、参数列表和函数体。class Date { public: Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } //private: int _year; int _month; int _day; }; bool operator(const Date d1, const Date d2) { return d1._year d2._year d1._month d2._month d1._day d2._day; }这里涉及到两个问题①这里的返回类型是根据我的运算符的功能来的比如这个等于运算符其是要判断是否相等所以我要返回一个bool值。名字就是operator后面要定义的运算符之后的参数列表和函数体就根据函数的功能来进行设计。②我为了在类外也能访问到私有的成员函数把它们都放成公有了这里还有几种解决办法1Date类提供getxxx函数 2友元函数 3重载为成员函数。这个问题我们下面紧接着就会进行讲解。• 运算符重载函数的参数个数要和该运算符作用的运算对象数量一样多。一元运算符要有一个参数二元运算符要有两个参数其中二元运算符的左侧运算对象传给第一个参数右侧运算对象传给第二个参数。调用函数方法如下//正常调用可读性高 d1 d2 //当然也可以显式调用 operator(d1,d2);• 如果一个运算符重载函数是成员函数时因为this指针的存在其第一个运算对象也就是二元运算符的左运算数默认传给隐式的this指针因此运算符重载作为成员函数时参数比运算对象少一个。下面演示一下重载为成员函数的写法class Date { public: bool operator(const Date d) { return _year d._year _month d._month _day d._day; } private: int _year; int _month; int _day; };可以看到参数只有一个了因为前面有一个隐含的this指针且其会指向调用这个函数的对象的地址。• 运算符重载后其优先级和结合性与对应的内置类型运算符保持一致。• 不能通过语法中没有的符号来创造新的运算符比如operator。•.*::sizeof?:.注意以上5个运算符不能重载。选择题常考记忆下一就行。• 重载运算符至少要有一个类类型的参数不能通过运算符重载去改变内置类型对象的运算符含义如int operator(int x, int y)• 一个类要重载哪些运算符是要看哪些运算符重载后有意义比如Date日期类重载operator-就有意义但是重载operator*就没有意义。• 重载--运算符时分为前置和后置运算符重载的函数名都是operator无法很好区分。所以C规定后置重载时在参数列表里增加一个int形参跟前置构成函数重载方便区分。Date Date::operator() { //... } Date Date::operator(int) { //... }注意①这里使用了声明和定义分离先在类内部写声明在外部写函数这个函数还是内部成员函数。②后置中参数列表里的int只用作占位用来和前置形成函数重载和区分无实际用途。• 重载和时要重载成全局函数因为如果重载成成员函数this指针默认抢占了第一个形参位置而第一个形参位置是左侧运算对象调用时就会变成: 对象cout不符合使用习惯和可读性class Date { public: Date operator(); Date operator(int); Date(int year 1, int month 1, int day 1) { _year year; _month month; _day day; } void operator(ostream _cout) { _cout _year / _month / _day endl; } private: int _year; int _month; int _day; }; int main() { Date d1(2026, 10, 5); Date d2(2000, 1, 1); d1 cout; return 0; }而重载为全局函数把ostream/istream放到第一个形参就可以了第二个形参位置为当前类类型的对象。此外要注意一点输入输出要支持连续的输入输出也就是cin i n; cout i n endl;而连续的输入输出的诀窍就是返回值每单个输入输出后就会返回一个cout或cin去进行下一次的输入或输出cin i n; //先cini,-返回cin再cinn; cout i n endl; //先couti,返回cout再去接下来的输出所以我们在实现时也要自己加入返回值这个实例在后续的日期类实现里完整实现。2.赋值运算符重载赋值运算符重载是一个默认成员函数用于完成两个已经存在的对象直接的赋值这里要注意和拷贝构造区分拷贝构造用于一个已经存在的对象去拷贝初始化一个要创建的对象而赋值运算符重载是两个对象都已存在后的赋值//拷贝构造 Date d3 d1; //赋值运算符的重载 d1 d2赋值运算符重载的特点1.赋值运算符重载是一个运算符重载规定必须重载为成员函数因其为默认的成员函数之一。赋值运算符重载的参数建议写成const当前类类型的引用否则传值传参会有拷贝。2.有返回值且建议写成当前类类型的引用引用返回可以提高效率跳过拷贝构造有返回值的目的是为了支持连续赋值和前文的/一样的场景。3.没有显式实现时编译器会自动生成一个默认赋值运算符重载默认运算符重载行为跟拷贝构造函数类似。都是对内置类型完成值拷贝/浅拷贝一个字节一个字节的拷贝对自定义类型成员变量会调用它自己的赋值重载函数。4.像Date这样的类成员变量全是内置类型且没有指向什么资源编译器自动生成的赋值运算符重载就可以完成需要的拷贝所以不需要我们显示实现赋值运算符重载。像Stack这样的类虽然也都是内置类型但是_a指向了资源编译器自动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我们的需求所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部主要是自定义类型Stack成员编译器自动生成的赋值运算符重载会调用Stack的赋值运算符重载也不需要我们显示实现MyQueue的赋值运算符重载。这里还有一个小技巧如果一个类显示实现了析构并释放资源那么他就需要显示写赋值运算符重载否则就不需要。这里也和拷贝构造类似。3.日期类的实现让我们现在使用所学的全部知识去实现一个日期类完成它的基本功能。这里也涉及到了const成员函数接下来就会讲解。//Date.h #includeiostream using namespace std; #includeassert.h class Date { friend ostream operator(ostream _cout, const Date d); friend istream operator(istream _cin, Date d); public: Date(int year 1, int month 1, int day 1); void Print() const; bool CheckDate() const; //因其要频繁调用所以不做声明和定义分离使其成为inline函数 int GetMonthDay(int year, int month) const { assert(month 1 month 12); int arr[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; if (month ! 2) { return arr[month]; } if ((year % 4 0 year % 100 ! 0) || year % 400 0) { return 29; } return 28; } //比较大小相等 bool operator(const Date d) const; bool operator(const Date d) const; bool operator(const Date d) const; bool operator(const Date d) const; bool operator(const Date d) const; bool operator!(const Date d) const; //日期天数日期天数 Date operator(int day); Date operator(int day) const; //日期-天数日期-天数 Date operator-(int day); Date operator-(int day) const; //日期-日期 int operator-(const Date d) const; //Date的自加和自减 Date operator(); Date operator(int); Date operator--(); Date operator--(int); private: int _year; int _month; int _day; }; //输入输出流的重载 ostream operator(ostream out, const Date d); istream operator(istream in, Date d); //Date.cpp #includeDate.h Date::Date(int year, int month, int day) { _year year; _month month; _day day; assert(!CheckDate()); } void Date::Print() const { cout _year / _month / _day endl; } bool Date::CheckDate()const { if (_month 12 || _month1 || _day GetMonthDay(_year, _month) || _day 1) { return false; } else { return true; } } bool Date::operator(const Date d) const { 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; } } return false; } bool Date::operator(const Date d) const { return _year d._year _month d._month _day d._day; } bool Date::operator(const Date d) const { return *this d || *this d; } bool Date::operator(const Date d) const { return d *this; } bool Date::operator(const Date d) const { return *this d || *this d; } bool Date::operator!(const Date d) const { return !(*this d); } Date Date::operator(int day) { if (day 0) { day -day; *this - day; return *this; } _day day; while (_day GetMonthDay(_year, _month)) { _day _day - GetMonthDay(_year, _month); _month 1; if (_month 12) { _month 1; _year 1; } } return *this; } Date Date::operator(int day) const { Date tmp *this; return tmp day; } Date Date::operator-(int day) { if (day 0) { day -day; *this day; return *this; } _day - day; while (_day 1) { _month - 1; if (_month 1) { _month 12; _year - 1; } _day _day GetMonthDay(_year, _month); } return *this; } Date Date::operator-(int day) const { Date tmp *this; return tmp - day; } int Date::operator-(const Date d) const { Date max *this; Date min d; int flag 1; if (max min) { max d; min *this; flag -1; } int n 0; while (min ! max) { min; n; } return flag * n; } Date Date::operator() { return *this 1; } Date Date::operator(int) { Date tmp *this; *this 1; return tmp; } Date Date::operator--() { return *this - 1; } Date Date::operator--(int) { Date tmp *this; *this - 1; return tmp; } ostream operator(ostream out, const Date d) { out d._year 年 d._month 月 d._day 日 endl; return out; } istream operator(istream in, Date d) { cout 请输入年月日 endl; while (1) { in d._year d._month d._day; if (!d.CheckDate()) { cout 输入信息不合法请重新输入 endl; } else { break; } } return in; }二.取地址运算符的重载1.const成员函数• 规定把const修饰的成员函数称之为const成员函数const修饰成员函数要放到成员函数参数列表的后面。int GetMonthDay(int year, int month) const;• 这里const实际修饰的是该成员函数的this指针表明不能对类的任何成员进行修改假设const修饰Date类的Print成员函数那Print隐含的this指针发生如下变化Date* const this - const Date* const this没加const修饰函数之前自带的const是修饰this本身的意思是你this就一直指向调用它的那个对象。现在又加一个const修饰的是*this指的是不能对this指向的对象本身进行改变不能去改变对象和其中的具体内容了。• 加上const修饰函数还有一个优点可以调用const修饰的对象了。const Date d1; Date d2; //这里如果Print函数没有加上const修饰会编译报错 d1.Print(); d2.Print();其原因在于d1在取地址后是const Date*类型的然后要把这个类型传给this指针若this指针没被const修饰则会权限放大编译报错。2.取地址运算符重载取地址运算符重载分为①普通取地址运算符重载和②const取地址运算符重载一般编译器自动生成的这两个函数就够我们使用了不需要去显式实现。除非一些很特殊的场景比如我们不想让别人去取到当前类对象的地址时就可以去显式实现一个返回一个空地址。因其为默认成员函数这两个也要重载成成员函数。class Date { public: Date* operator() { return this; //return nullptr; } const Date* operator()const//通过这个const修饰this指针完成函数重载 { return this; //return nullptr; } private: int _year; int _month; int _day; };三.结语类和对象中到这里就结束了我们完成了对六个默认成员函数的基本学习但是并不完全如构造函数在类和对象下还有要补充的知识点让我们努力前进吧

相关新闻

成都事故车保险定损去哪里?双流理赔车辆凹陷无痕修复认准超佩七车匠 (双流旗舰店)

成都事故车保险定损去哪里?双流理赔车辆凹陷无痕修复认准超佩七车匠 (双流旗舰店)

成都汽车保有量持续攀升,交通事故、冰雹灾害时有发生,不少车主车辆受损走完保险定损之后,都在搜索双流区冰雹坑修复哪家好、双流区冰雹坑修复哪家强、双流区冰雹坑修复哪家专业、双流区冰雹坑修复哪家靠谱。在东升汽车服务商圈,超…

2026/10/10 12:08:43 阅读更多 →
2026 深圳网站搭建公司推荐:架构方案、部署环境与上线保障的十家服务商解析

2026 深圳网站搭建公司推荐:架构方案、部署环境与上线保障的十家服务商解析

网站搭得好不好,平时看不出来,出事的时候一眼就分高下——访问一慢、证书一过期、数据一丢,前面做的页面再漂亮也救不了场。本文从架构方案、部署环境与上线保障三个层面,梳理深圳十家值得关注的网站搭建服务商:易百讯…

2026/10/10 12:08:43 阅读更多 →
基于PJ85718DM与STM32F410RB的温度监测节点设计与实现

基于PJ85718DM与STM32F410RB的温度监测节点设计与实现

1. 项目缘起与整体设计思路温度监测这件事,听起来像是电子入门第一课的内容,但真正把它做到“本地看得见、远程收得到、长期跑得稳”,中间要踩的坑远比想象中多。我这次做的项目,核心就是用一颗PJ85718DM温度传感芯片搭配STM32F41…

2026/10/10 12:08:43 阅读更多 →

最新新闻

网页消息提醒音JS落地指南:自动播放解锁与实战避坑

网页消息提醒音JS落地指南:自动播放解锁与实战避坑

简介:网页消息提醒音js是一份面向网页前端开发者的实用示例资源,主要解决页面在收到新消息或事件时准确播放提示音的问题,适合在实时通讯、社交网络、在线协作等需要即时感知的场景中使用。资源压缩包共包含3个文件,有可直接运行的…

2026/10/10 15:19:38 阅读更多 →
Postman × Codex:如何将API集合封装成智能体Skill

Postman × Codex:如何将API集合封装成智能体Skill

直接上一个我最近在空隙时间里折腾完的东西:把 Postman 里的 API 集合,做成 Codex 可以直接调用的智能体 Skill。简单说,就是让 AI 代理能像人一样用 Postman 里的接口去查数据、发请求、跑流程,而不是只能对着文档“空谈”。这个…

2026/10/10 15:19:38 阅读更多 →
手工构造TINY词法分析器:从词法规则到Java实现与踩坑指南

手工构造TINY词法分析器:从词法规则到Java实现与踩坑指南

简介:面向编译原理课程设计与实验场景,这份资源聚焦TINY语言词法分析器的手工构造,适合正在学习编译器前端、需要完成类似实验的本专科生及自学者。内容围绕C/C实现展开,涵盖TINY词法规则识别、Token类型定义、确定有限状态自动机…

2026/10/10 15:19:38 阅读更多 →
ReelMimic完全指南:如何用最爱的视频当模板,一键生成同款风格的AI视频

ReelMimic完全指南:如何用最爱的视频当模板,一键生成同款风格的AI视频

【免费下载链接】reelmimic Show it a video you love. Get a new video in the same style. An AI crew (Claude Code or Codex) plans, builds and reviews it with you. 项目地址: https://gitcode.com/gh_mirrors/re/reelmimic 点击查看 免费下载 ReelMimic 是…

2026/10/10 15:18:38 阅读更多 →
10 分钟上手:给 Claude Code 装上 ai-memory,让 Agent 跨会话记住你的项目偏好

10 分钟上手:给 Claude Code 装上 ai-memory,让 Agent 跨会话记住你的项目偏好

10 分钟上手:给 Claude Code 装上 ai-memory,让 Agent 跨会话记住你的项目偏好 【免费下载链接】ai-memory Solution for long term memory for agent coding CLIs and to facilitate handoff between different agent vendors 项目地址: https://gitc…

2026/10/10 15:18:38 阅读更多 →
cal.diy 集成 Discord:静态会议链接型应用从配置到代码的完整拆解

cal.diy 集成 Discord:静态会议链接型应用从配置到代码的完整拆解

后端前端企业应用 【免费下载链接】cal.diy Scheduling infrastructure for absolutely everyone. 项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy 点击查看 免费下载 本指南以 cal.diy(Cal.com 开源调度平台)应用商店中的 Disc…

2026/10/10 15:18:37 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →