类与对象(中)

目录

赋值运算符重载

运算符重载

赋值运算符重载

前置++和后置++重载

日期类的实现(前置后置++也在里面)

const 成员

​编辑 取地址及const取地址操作符重载


赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
需要注意的是:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
  • 藏的this
  •   .*     ::     sizeof    ?:   .   注意以上5个运算符不能重载。

d1 - d2计算两个日期之间相差的天数有意义

d1+d2两个日期相加没有意义

d1*d2日期相乘没有意义

所以我们知道了一个类重载哪些运算符是看需求的,看重载有没有意义。

#include<iostream>
using namespace std;class Date
{
public:int GetMonthDay(int year, int month){static int arr[13] = { 0,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 arr[month];}Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//private:int _year;int _month;int _day;
};bool operator==(const Date& d1 , const Date& d2)
{if (d1._year == d2._year){if (d1._month == d2._month){if (d1._day == d2._day){return true;}}}return false;
}int main()
{Date d1(2024, 4, 15);Date d2 = d1;Date d3;//显式调用operator==(d1, d2);//直接写,转换调用,编译器会转换operator==(d1, d2);d1 == d2;return 0;
}

但是我们能看到这样写是不够好的 重载成全局函数无法访问私有成员 因此就可以重载为成员函数。

#include<iostream>
using namespace std;class Date
{
public:int GetMonthDay(int year, int month){static int arr[13] = { 0,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 arr[month];}Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d1 , const Date& d2){if (d1._year == d2._year){if (d1._month == d2._month){if (d1._day == d2._day){return true;}}}return false;}//private:int _year;int _month;int _day;
};//bool operator==(const Date& d1 , const Date& d2)
//{
//	if (d1._year == d2._year)
//	{
//		if (d1._month == d2._month)
//		{
//			if (d1._day == d2._day)
//			{
//				return true;
//			}
//		}
//	}
//	return false;
//}int main()
{Date d1(2024, 4, 15);Date d2 = d1;Date d3;//显式调用operator==(d1, d2);//直接写,转换调用,编译器会转换operator==(d1, d2);d1 == d2;return 0;
}

运算符重载和赋值运算符重载全部代码在后面

赋值运算符重载

赋值运算符重载格式

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义

拷贝构造与赋值重载的区别:

赋值重载:一个已经存在的对象拷贝赋值给另一个已经存在的对象

为什么返回值类型是 类引用 而不是 void 呢? 

 

如果是void 的话则会出现如下情况。所以我们需要一个返回值 *this . 

接下来来看

为什么打印出来是随机值。

下面这个为什么是正确的

解释如下: 

 所以出了作用域,返回对象还在没有析构,那就可以引用返回,减少拷贝。

返回对象生命周期到了,会析构,传值返回。

返回对象生命周期没到,不会析构,传引用返回。

前置++和后置++重载

前置++:返回+1之后的结果
后置++:
前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1

日期类的实现(前置后置++也在里面)

class Date
{
public:int GetMonthDay(int year, int month){static int arr[13] = { 0,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 arr[month];}Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d){if (_year == d._year){if (_month == d._month){if (_day == d._day){return true;}}}return false;}Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}bool 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 operator==(const Date& d){if (_year == d._year){if (_month == d._month){if (_day == d._day){return true;}}}return false;}bool operator>=(const Date& d){if (*this > d || *this == d){return true;}return false;}bool operator<(const Date& d){if (*this >= d){return false;}return true;}bool operator<=(const Date& d){if (*this > d){return false;}return true;}Date& operator+=(int i){_day += i;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){++_year;_month = 1;}}return *this;}Date operator+(int i){Date tmp = *this;tmp += i;return tmp;}Date& operator-=(int i){_day -= i;while (_day <= 0){_day += GetMonthDay(_year, --_month);if (_month == 0){_year--;_month = 12;}}return *this;}Date operator-(int i){Date tmp = *this;tmp -= i;return tmp;}bool operator != (const Date& d){if (*this == d){return false;}return true;}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;}int operator-(const Date& d){int flag = 1;int n = 0;Date d1 = *this;Date d2 = d;if (*this < d){Date d2 = *this;Date d1 = d;flag = -1;}while (d1 != d2){++d2;n++;}return n * flag;}void print(){cout << _year << ' ' << _month << ' ' << _day << endl;}~Date(){this->_year = -1;this->_month = -1;this->_day = -1;}private:int _year;int _month;int _day;
};

接下来又有一个问题:

 由于cout 只能输出内置类型有没有什么办法能让他输出自定义内型呢!

我们可以定义如下运算符重载函数在类中。

	ostream& operator<<(ostream& out)//这里需要+引用因为istream 和ostream不支持拷贝构造{out << _year << "年" << _month << "月" << _day << "日" << endl;return out;}

可是他还是不符合逻辑的: 

因为this 指针的原因我们需要像下面这样输出,可这样是不符合逻辑的。 

因为this 指针的原因我们需要把函数定义到全局中 

这样的话又有了新的问题私有成员变量不可访问。

我们就可以通过友元函数声明来告诉编译器这个函数是我们的朋友可以调用。 

除了cout之外还有一个 cin 我们也可以来写一下。

const 成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数
隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

 

	void print()const{cout << _year << "年" << _month << "月" << _day << "日" << endl;}

 取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。


这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需
要重载,比如想让别人获取到指定的内容!

class A
{
public:A* operator&(){return this;}const A* operator&() const{return this;}
private:int _a = 1;int _b = 1;int _c = 1;
};int main()
{A aa1;const A aa2;cout << &aa1 << endl;cout << &aa2 << endl;
}

这两个默认成员函数编译器会自己实现一般不需要自己去实现。

感谢大家的观看!

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

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

相关文章

【python】python天气气候数据抓取分析可视化(源码+数据+可视化+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Redis入门到通关之ZSet命令

文章目录 ⛄概述⛄常见命令有⛄RedisTemplate API❄️❄️ 向集合中插入元素&#xff0c;并设置分数❄️❄️向集合中插入多个元素,并设置分数❄️❄️按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部❄️❄️获得指定元素的分数❄️❄️返回集合内的成员个数❄️❄…

汇编基础-----通过x64dbg了解什么是堆栈

汇编基础-----通过x64dbg了解什么是堆栈 什么是堆栈 在汇编语言中&#xff0c;堆栈&#xff08;stack&#xff09;是一种用于存储临时数据和执行函数调用的内存结构。堆栈是一种后进先出&#xff08;Last-In-First-Out, LIFO&#xff09;的数据结构&#xff0c;通常用于保存函…

【Docker系列】容器访问宿主机的Mysql

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

前端标记语言HTML

HTML&#xff08;HyperText Markup Language&#xff09;是一种用于创建网页的标准标记语言。它是构建和设计网页及应用的基础&#xff0c;通过定义各种元素和属性&#xff0c;HTML使得开发者能够组织和格式化文本、图像、链接等内容。 HTML的基本结构 文档类型声明&#xff0…

QT drawPixmap和drawImage处理图片模糊问题

drawPixmap和drawImage显示图片时&#xff0c;如果图片存在缩放时&#xff0c;会出现模糊现象&#xff0c;例如将一个100x100 的图片显示到30x30的区域&#xff0c;这个时候就会出现模糊。如下&#xff1a; 实际图片&#xff1a; 这个问题就是大图显示成小图造成的像素失真。 当…

【笔试】02

TCP TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议 它能够提供以下服务&#xff1a; 可靠传输 通过序列号、确认应答、重传机制等确保数据完整、准确地从发送端传输到接收端。 三次握手&#xff1a; 点对点全双工面向字节流…

1260. 二维网格迁移

1260. 二维网格迁移 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;错误经验吸取 原题链接&#xff1a; 1260. 二维网格迁移 https://leetcode.cn/problems/shift-2d-grid/description/ 完成情况&#xff1a; 解题思路&#xff1a; 这…

使用稳压管和三极管射极输出器电路驱动PMOS

当电源电压大于PMOS 管的最大栅源电源时&#xff0c;不能直接把栅极拉到地&#xff0c;需要一点特殊的电路来限制栅极驱动电压。有的地方是用电阻分压器做的&#xff0c;比如这种&#xff1a; NPN 三极管导通时&#xff0c;MOS 管栅极电压是两个电阻中间的电压。这种设计最大的…

106.从中序与后序遍历构造二叉树

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 思路&#xff1a; 中序遍历数组中&#xff0c;找到一个根节点&#xff0c;那么其前为其左子树&a…

大模型用到的位置编码汇总(面试)

不同于RNN、CNN等模型&#xff0c;对于Transformer模型来说&#xff0c;位置编码的加入是必不可少的&#xff0c;因为纯粹的Attention模块是无法捕捉输入顺序的&#xff0c;即无法区分不同位置的Token。为此我们大体有两个选择&#xff1a;想办法将位置信息融入到输入中&#x…

Office 365卡顿怎么办?SD-WAN可以解决

随着数字化浪潮的推进&#xff0c;Office 365等云办公应用已成为企业日常运营不可或缺的工具。然而&#xff0c;许多企业在使用Office 365时遭遇了网络卡顿的难题&#xff0c;给工作人员带来诸多不便。随着SD-WAN技术的成熟和普及&#xff0c;这一难题得到了有效的解决。 Offic…

四足机器人应用篇之solidwork导出URDF

欢迎关注微信公众号 “四足机器人研习社”&#xff0c;本公众号的文章和资料和四足机器人相关&#xff0c;包括行业的经典教材、行业资料手册&#xff0c;同时会涉及到职业知识学习及思考、行业发展、学习方法等一些方面的文章。 |1.URDF介绍 一个URDF pakage示例 urdf是ROS用于…

ABAP MESSAGE 常用的类型

类型文本描述A终止处理终止&#xff0c;用户必须重启事务X退出与消息类型A 类似&#xff0c;但带有程序崩溃 MESSAGE_TYPE_XE错误处理受到干扰&#xff0c;用户必须修正输入条目,左下角提示!W警告处理受到干扰&#xff0c;用户可以修正输入条目,左下角提示!I信息处理受到干扰&a…

数据库讲解---(数据更新、视图、数据控制)【MySQL版本】

目录 前言 一.数据更新 1.1插入数据 1.1.1插入单个元组 1.1.2将一个新学生记录(学号:091530,姓名:夏雨,性别:男,籍:海南,出生年份:1999,学院:计算机)插入到学生表中 1.1.3插入子查询结果 1.1.4有一个表“DEPT”(SDEPT CHAR(20),AVG_AGE SMALLINT)表示每个学院的学生的平…

网络安全-自学笔记

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 我在之前的回答中&#xff0c;我都一再强调不要以编程为基础再开始学习网络安全&#xff0c;一般来说&#xff0c;学习编程不但学习周期长&#xff0c;而…

【力扣TOP100热题图解】T1.两数之和

题目链接点这里—— 力扣&#xff08;LeetCode&#xff09;​​​​​​ 法一&#xff1a;暴力枚举 最容易想到的方法是枚举数组中的每一个数 x&#xff0c;寻找数组中是否存在 target - x。 当我们使用遍历整个数组的方式寻找 target - x 时&#xff0c;需要注意到每一个位…

【Linux】磁盘管理和文件系统

目录 一、硬盘 1.硬盘结构 2.结构类型 二、MBR与磁盘分区 1.MBR主引导记录 2.磁盘分区结构 三、文件系统类型 四、linux系统添加并使用新硬盘的步骤 1.添加新的硬盘 2.刷新识别 3.进行分区 4.格式化&#xff0c;创建文件系统 5.挂载使用 一、硬盘 1.硬盘结构…

SpringBoot整合消息中间件(ActiveMQ,RabbitMQ,RocketMQ,Kafka)

消息中间件 消息消息队列JMS AMQPMQTTKafka Spring整合消息队列模拟消息队列的工作流程Spring整合ActiveMQSpring整合RabbitMQ直连交换机模式主题交换机模式 Spring整合RocketMQSpring整合kafka 消息 消息的发送方&#xff1a;生产者 消息的接收方&#xff1a;消费者 同步消息…

基于SSM项目高校在线请假与审批系统

采用技术 基于SpringBoot框架实现的web的智慧社区系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 简介 本系统实现了管理员&#xff0c;教师&#xff0c;学生三个模…