C++学习————第六天 (运算符重载 const成员 取地址)

 这一篇我们来补齐上一天的 留下的三个默认成员函数

//上一天内容 :

nullicon-default.png?t=N7T8https://blog.csdn.net/island1314/article/details/137371086?spm=1001.2014.3001.5502


1、重载

1.1 运算符重载


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

比如 Date  日期类返回值 

 bool operator < (const Date& d1, const Date& d2)
 Date operator++(Date &d) // 返回值函数 Date

 d1 < d2  -> bool
 ++d1  -> Date
 d1 - d2  -> int 有意义
 d1 - 100 -> Date   d1 + 100-> Date

注意:
1、不能通过连接其他符号来创建新的操作符(必须是c语言和c++有的操作符):比如 operator@ 就不行
2、重载操作符必须有一个类类型参数 : 比如int operator-(int i,int j)就不可以
3、用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义 (但是有些情况中是可以改变的)
4、作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
5、  .*()  ::(域作用限定符)  sizeof (sizeof运算符)  ?: (三目操作符)  . ( 对象 点) 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

.* 运算符的使用 

 //  哪些运算符需要重载: 按需重载

 d1+d2没有意义,d1*d2没有意义,因此一个类重载哪些运算符要看需求,看重载是否有价值和意义

运算符重载样例代码:

        这里会发现运算符重载成全局的就需要成员变量是公有的,那么问题来了,假如把类的成员变量改为私有 则 operator 会报错 ,此时封装性如何保证?
 这里其实可以用我们后面学习的友元解决,或者干脆重载成成员函数。

即当重载成为全局 无法访问类的私有成员解决方法:

1、提供这些成员get 和 set

2、友元

3、重载成为成员函数 (一般使用这种)

显示写出成员函数,其实可以不用显示写

成员函数的调用

下面为上面两者汇编, 因此可知转换调用等价于上面的调用 

当全局 和 局部 同时存在的时候,优先调用类里面的,不会报错。


1.2 赋值运算符重载

赋值重载理解:

原因是因为 拷贝构造 是把一个已经存在的对象,拷贝初始化另一个要创建初始化的对象

            赋值重载(赋值拷贝)是把一个已经存在的对象,拷贝赋值给是把另一个已经存在的对象

 a、赋值运算符重载格式

1、参数类型:const T&,传递引用可以提高传参效率
2、返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

3、检测是否自己给自己赋值
4、返回 *this :要复合连续赋值的含义

this 指针返回:

 

但是这个不能实现   

因此可以改成 

传值返回 和 引用返回区别: 

代码演示:

    由于打印结果 ref 和 d 地址相同,易知在引用返回中 ref 是 d 的别名 

但是再加一个下面的全局函数,可以发现引用返回的问题

但是当我们改成  

    出了函数作用,返回对象还在,才能引用返回,减少拷贝
    a、返回对象生命周期到了,会析构,传值返回
    b、返回对象生命周期没到了,不会析构,传引用返回

    总结:返回对象是一个局部对象或者临时对象,出了当前函数作用域,就析构销毁了,那么就不能引用返回,  用引用返回是存在风险的,因为引用对象在func函数栈帧已经销毁了,虽然引用返回可以减少一次拷贝,但是出了函数作用,返回对象还在,才能引用返回

正确代码演示 :

class Date
{
public:
	Date(int year = 1900, 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;
	}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;
	}
private:
	int _year;
	   int _month;
	   int _day;
};

b、赋值运算符只能重载成类的成员函数不能重载成全局函数

c、用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实
现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2;
	s2 = s1;
	return 0;
}

注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必
须要实现。

d、六大比较运算符的实现

函数声明:

函数实现:

bool Date::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) return _day < d._day;
	}
	return false;
}

// d1 <= d2
bool Date:: operator<=(const Date& d)
{
	return *this < d || *this == d; //因为我们对小于 和 等于进行了构造
}

bool Date:: operator>(const Date& d)
{
	return!(*this <= d);
}

bool Date:: operator>=(const Date& d)
{
	return !(*this < d);
}
bool Date:: operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

bool Date:: operator!=(const Date& d)
{
	return !(*this == d);
}

1.3  前置++和后置++重载

样例代码1:
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// 前置++:返回+1之后的结果
	// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
	Date& operator++()
	{
		_day += 1;
		return *this;
	}
	// 后置++:
	// 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
	// C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
		// 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this + 1
		//    而temp是临时对象,因此只能以值的方式返回,不能返回引用
	Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d;
	Date d1(2022, 1, 13);
	d = d1++;// d: 2022,1,13  d1:2022,1,14 
	d = ++d1; // d: 2022,1,15  d1:2022,1,15
	return 0;
}
样例代码2:

这里我们用到了代码复用,可以仔细看看

// ++d1
Date& Date:: operator ++()
{
	*this += 1;
	return *this;
}

// ++d1
Date Date:: operator++(int i)
{
	cout << i << endl;
	Date tmp(*this);
	*this += 1;
	return tmp;
}


 两个交换 不会报错 打印也没有问题
 ++d1
//Date Date:: operator ++()
//{
//	Date tmp(*this);
//	*this += 1;
//	return tmp;
//}
//
 d1++
//Date& Date:: operator++(int i)
//{
//	*this += 1;
//	return *this;
//}


Date& Date:: operator --()
{
	*this -= 1;
	return *this;
}

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

代码复用

1.4 流插入流提取

之所以不用 printf 和 scanf 是因为他俩只支持内置类型

1、定义在类的函数

此时类的成员变量可以为私有

函数名:

 函数实现:

实参传递:

结果演示:

2、全局函数:

变成全局的时候,这时的 成员变量需要是公有的

函数名:

函数实现:

实参传递:

结果演示:

3、友元函数

函数名:

只需要改变函数名即可,就可以在私有成员变量下使用,函数实现和结果演示均不发生改变

分析:

实参顺序(操作数顺便本质上就是实参顺序)


2、const成员

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

代码1 比如:

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	void Print() const
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
void Test()
{
	Date d1(2022, 1, 13);
	d1.Print();
	const Date d2(2022, 1, 13);
	d2.Print();
}

代码2演示 如下:

 const 不能修饰+= ,因为会使*this无法修改,因此函数中需要修改成员的都不能使用const

代码如下:

若要加 const 对前面的函数代码实现进行部分修改即可,如:


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

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

#include <iostream>

using namespace std;

class A
{
public:
	// 我们不实现,编译器也会实现,一般不需要我们自己实现
	A* operator&()
	{
		cout << "A* operator&()" << endl;

		return this;
	}

	const A* operator&() const
	{
		cout << "const A* operator&() const" << endl;
		return this;
	}

private:
	int _a1 = 1;
	int _a2 = 2;
	int _a3 = 3;
};

int main()
{
	A aa1;
	const A aa2;

	cout << &aa1 << endl;
	cout << &aa2 << endl;

	return 0;
}

除非不想让别人取到这个类型对象的真实地址,给假地址

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


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AUTOCAD输出或打印PDF文件时,如何将图形居中且布满图纸?

AUTOCAD输出或打印PDF文件时,如何将图形居中且布满图纸? 如下图所示,我们打开一份DWG格式的图纸文件,然后点击上方的“打印“图标, 如下图所示, 打印机/绘图仪这里选择“DWG To PDF“; 图纸尺寸:这里以普通的A4纸为例进行说明; 打印比例选择“布满图纸“; 打印偏移…

uniapp 组件传值

uniapp 组件传值 父传子子传父 uniapp 组件传值 父传子 在uniapp中&#xff0c;组件传值主要通过props进行。以下是一个简单的例子&#xff1a; 首先&#xff0c;创建一个组件MyComponent.vue&#xff1a; <template><view><text>{{ message }}</tex…

计算机网络(六)应用层

应用层 基本概念 服务器端&#xff08;Server&#xff09;&#xff1a; 服务器是网络中提供服务的计算机或软件程序。服务器通常具有更高的性能、更大的存储空间和更高的带宽&#xff0c;用于提供各种服务&#xff0c;如文件存储、数据库管理、Web托管、电子邮件传递等。服务…

Redis 缓存预热、预热数据选取策略、缓存保温、性能边界

缓存预热 热点数据预热&#xff1a;根据业务分析或统计数据&#xff0c;确定热点数据&#xff08;经常被访问的数据&#xff09;&#xff0c;并将其提前加载到Redis缓存中。可以根据访问频率、访问量或其他业务指标来确定热点数据。定时预热&#xff1a;可以设置定时任务&…

住宅IP代理和机房IP代理之间的区别?

一、什么是数据中心/机房IP代理&#xff1f; 数据中心/机房IP代理是使用数据中心拥有并进行分配和管理的IP的代理&#xff0c;俗称机房IP代理。 二、数据中心/机房IP代理的特点 与住宅代理通过使用ISP拥有和分配的IP地址的设备路由请求的情况不同&#xff0c;数据中心代理利…

什么是线程?线程和进程谁更弔?

第一个参数是所创建进程的pid。 第二个是线程的属性。 第三个参数是返回值为void*&#xff0c;参数也为void*的函数指针。 第四个参数是给第三个参数的参数&#xff0c;也就是给给函数传参。 #include<iostream> #include<pthread.h> #include<unistd.h>…

8thWall vs. AR.js

对于熟悉 JavaScript、WebGL 和 HTML5 等 Web 技术的数字创作者来说&#xff0c;8th Wall 提供了功能丰富且强大的 AR 开发平台&#xff0c;尽管价格较高。 然而&#xff0c;新手开发人员和专注于基于标记的 AR 的开发人员可能会发现 AR.js 更易于使用且更经济实惠。 1、8th Wa…

利用redis和fastapi实现本地与平台策略进行交互

redis在pandas一文有详细使用方法(一文教会pandas-CSDN博客)&#xff0c;具体可视化软件有redisstudio等。它是一个由 Salvatore Sanfilippo 写的 key-value 存储系统&#xff0c;是跨平台的非关系型数据库。 Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络…

看图找LOGO,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建生活场景下的商品商标LOGO检测识别系统

日常生活中&#xff0c;我们会看到眼花缭乱的各种各样的产品logo&#xff0c;但是往往却未必能认全&#xff0c;正因为有这个想法&#xff0c;这里我花费了过去近两周的时间采集和构建了包含50种商品商标logo的数据集&#xff0c;基于YOLOv8全系列的参数模型开发构建了对应的检…

02_JavaWeb中的Tomcat(详解)

文章目录 Tomcat1, 概述1.1 安装1.2 目录结构1.3 启动/停止 2, 资源部署2.1 直接部署: 主要和重要的方式2.2 虚拟映射: 重要2.2.1 方式一:2.2.1 方式二: 2.3 原理解析 3, Tomcat组件3.1 Connector3.2 Engine3.2.1 Host3.2.1.1 Context 4, 其它: 重要4.1 设置 Tomcat 1, 概述 w…

OSPF - 链路状态路由协议

IGP 外部网关路由协议&#xff1a; OSPF &#xff0c; IS-IS EGP 内部网关路由协议&#xff1a; BGP 协议算法&#xff1a; 距离矢量路由协议 链路状态路由协议 lsdb:链路状态数据库 - 存放lsa的地址 RIP&#xff1a;有方向的矢量&#xff0c;距离矢量路由协议&#xf…

通过Maven导入本地jar包

1.创建lib文件夹&#xff0c;把jar包放到文件夹里面 2.在pom里导入依赖 导入完成

政安晨:【深度学习神经网络基础】(九)—— 在深度学习神经网络反向传播训练中理解梯度

目录 简述 理解梯度 什么是梯度 计算梯度 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 简述 在深度…

基于Zookeeper 简单实现分布式任务协调组件

一、什么是 Zookeeper ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&#xff0c;是Hadoop和Hbase的重要组件。 它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维…

死磕GMSSL通信-java/Netty系列(二)

死磕GMSSL通信-java/Netty系列(二) 在上一篇文章中,我们探讨了如何利用C/C++实现国密通信。而本文将聚焦于Java环境下,特别是基于Netty框架,如何实现与国密系统的安全通信。为了确保新项目遵循最新的国密标准,我们将优先推荐使用GB/T 38636-2020(TLCP)协议。对于Java开…

[C++][算法基础]二分图的最大匹配(匈牙利算法)

给定一个二分图&#xff0c;其中左半部包含 n1 个点&#xff08;编号 1∼n1&#xff09;&#xff0c;右半部包含 n2 个点&#xff08;编号 1∼n2&#xff09;&#xff0c;二分图共包含 m 条边。 数据保证任意一条边的两个端点都不可能在同一部分中。 请你求出二分图的最大匹配…

天池酒瓶瑕疵检测数据集分析及完整baseline

以下内容为还没思路的小伙伴牵个头提供一个demo,大佬勿喷,线上成绩0.7,留空间给小伙伴们发挥自己的力量 ps:markdown不怎么熟悉,代码中如有明显缩进问题,自行斟酌改正,编辑好几次都改不过来,请原谅.... 数据分析瑕疵大类: 瓶盖瑕疵、标贴瑕疵、喷码瑕疵、瓶身瑕疵、酒液瑕疵瑕…

会议室预约小程序开源版开发

会议室预约小程序开源版开发 支持设置免费预约和付费预约、积分兑换商城、积分签到等 会议室类目&#xff0c;提供多种类型和设施的会议室选择&#xff0c;满足不同会议需求。 预约日历&#xff0c;展示会议室预约情况&#xff0c;方便用户选择空闲时段。 预约记录&#xff0…

机器学习实验------决策树

第1关&#xff1a;什么是决策树 任务描述 本关任务&#xff1a;根据本节课所学知识完成本关所设置的选择题。 第2关&#xff1a;信息熵与信息增益 任务描述 本关任务&#xff1a;掌握什么是信息增益&#xff0c;完成计算信息增益的程序设计。 import numpy as npdef calcIn…

聚道云软件连接器助力企业实现滴滴出差报销自动化

一、客户介绍 某机械有限公司是一家在机械设备制造领域拥有深厚底蕴和卓越实力的企业。自公司成立以来&#xff0c;该公司始终秉承创新、务实、高效的发展理念&#xff0c;专注于机械设备的研发、生产和销售。经过多年的发展&#xff0c;公司已成为国内机械行业的佼佼者&#…