类与对象(中)

目录

赋值运算符重载

运算符重载

赋值运算符重载

前置++和后置++重载

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

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,一经查实,立即删除!

相关文章

Android R framework修改低电量关机值为2%

问题背景 在R的系统rom产品开发中,在系统关于低电量关机的值,每个平台都不同,根据实际开发底层硬件的要求看实际情况来调整这个值,所以需要分析相关的电量变化执行的代码流程,来实现这个功能。 修改关键类 frameworks\base\services\core\java\com\android\server\Batt…

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

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

搜索相关知识点

记忆化搜索 记忆化搜索&#xff08;Memory search&#xff09;是一种结合了搜索和动态规划思想的算法策略。其基本思想是在搜索过程中&#xff0c;对于已经计算过的状态&#xff0c;将其结果保存下来&#xff0c;以便在后续的计算中可以直接使用&#xff0c;而不需要重新进行计…

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 的首页,持续学…

聊聊功能安全软件工具鉴定

功能安全中对于软件工具是有要求的&#xff0c;需要进行分类&#xff0c;当该工具为TCL2或者TCL3时&#xff0c;需要额外的信息支持&#xff0c;常用的方式有以下两种&#xff1a; 工具通过功能安全认证自己做测试&#xff0c;开发说明书等&#xff08;适用于自研的工具&#…

上海人工智能实验室代表的国家科研模式创新

本文转载自AI科技评论,真实性由 AI科技评论 负责。 文章目录 1. 人工智能科研模式创新2. 候选人特征Reference2023 年 12 月,上海人工智能实验室第一位主任汤晓鸥意外逝世。汤博士的突然离世令人惋惜,其离世后,上海人工智能实验室的主任位置也一直空缺至今。 1. 人工智能科…

前端标记语言HTML

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

Tomcat 8.5.100 配置多证书多域名

Tomcat多证书多域名必须是Tomcat 8.5以上版本 配置server.xml <?xml version1.0 encodingutf-8?><Server port"8005" shutdown"SHUTDOWN"><Listener className"org.apache.catalina.startup.VersionLoggerListener" /><…

Docker搭建Fleet

Fleet 是一个高度可伸缩的容器管理工具&#xff0c;它允许用户在一组机器上管理容器。它的设计目的是为了简化在多个Docker宿主之间部署和管理容器的过程。Fleet 可以在整个集群中自动分配资源&#xff0c;确保应用程序的高可用性&#xff0c;并提供服务发现的功能。 应用场景…

Android USB TP方向修改

搜集的一些关于Android USB TP的方向修改的代码&#xff0c;X to Y , X反转 &#xff0c; Y反转&#xff0c;双触屏配置&#xff0c;双屏异触等。 diff --git a/kernel/drivers/hid/hid-multitouch.c b/kernel/drivers/hid/hid-multitouch.c old mode 100644new mode 100755 i…

EtherCAT主站SOEM -- 29 -- STM32F767-SOEM通过 CSP模式(周期同步位置模式)控制一个电机转圈圈

EtherCAT主站SOEM -- 29 -- STM32F767-SOEM通过 CSP模式(周期同步位置模式)控制一个电机转圈圈 0 QT-SOEM视频预览及源代码下载:0.1 QT-SOEM视频预览0.2 QT-SOEM源代码下载1 程序文件修改替换1.1 allvalue.h1.2 allvalue.c1.3 motrorcontrol.h1.4 motrorcontrol.cpp1.5 main…

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…

(delphi11最新学习资料) Object Pascal 学习笔记---第9章第6节(嵌套异常和 InnerException机制)

9.6 异常的高级功能 ​ 除非你对这门语言已经有了很好的了解&#xff0c;否则第一次阅读这部分内容时最好跳过。在此之前&#xff0c;你可以先阅读下一章&#xff0c;将来再回到这一部分。 ​ 在本章的最后一部分&#xff0c;我将介绍一些与异常处理相关的高级主题。我将介绍…

嵌入式学习——Linux基础——day1

1. linux基础命令 1.1 ls 查看当前目录下的所有文件 ls -l 查看文件的详细信息 ls -a 查看当前目录下的所有文件&#xff08;包含隐藏文件&#xff09; 1.2 touch 创建一个空的普通文件 1.3 rm 删除一个普通文件 rm -rf 删除非…