【c++】类和对象(中)

【c++】类和对象(中)

  • 默认成员函数
    • 初始化和清理
      • 构造函数
        • 重载
        • 分类
        • 使用场景
      • 析构函数
        • 使用场景
    • 拷贝赋值
      • 拷贝构造函数
        • 使用场景
        • 浅拷贝与深拷贝
      • 赋值重载
        • 赋值重载和拷贝构造函数的区别
        • 使用场景
    • 取地址重载

本篇博客主要讲:六个默认成员函数

默认成员函数

在这里插入图片描述
这里为什么叫默认成员函数?

从默认可知,它们是类默认有的成员函数,也就是说是必有的
那如果是用户漏写其中几个的情况下,大胆点,甚至是空类呢?

都说是默认成员函数了,就是说:

当用户没有显式实现,系统就会自己去生成的函数,就叫默认成员函数

初始化和清理

当我们写C的时候,特别用C写数据结构的时候,比如说栈,链表,顺序表这种。
大家都或许多多少少会漏写初始化函数和销毁函数
其实初始化函数忘写还算好,至少程序跑不过去,调试就能看出来

但是销毁函数就不一样了,要是你申请的空间没有释放,导致内存泄漏
编译器甚至检查不出来,所以说销毁函数不写还是很严重的

祖师爷深知这点,于是便设置了专门用来初始化和清理的成员函数。
在函数开始时与结束时,会进行自动调用。

构造函数

构造函数看起来意思时向内存中申请空间的函数。
但是它的主要任务还是初始化对象。

有了它,你就再也不用担心那该死的初始化函数忘记调用了
那这么牛的函数,能让系统自动去调用,总应该和普通函数有点不同吧

没错,它就是特殊的成员函数
因为他是要被系统识别,这样才能被特殊调用,所以在命名上它是高贵的和类同名

例:

class test
{
public:
	test()
	{
		_x = 0;
		_y = 0;
	}
	int _x;
	int _y;
};

这里的test()就是test类的构造函数,因为是构造函数,所以它没有返回值,并且不用写void类型

它和类同名,在我们创建对象的时候,编译器就会自动调用这个构造函数。
在这里插入图片描述这里我们就可以看到在我们创建对象的时候,t1就自动去调用构造函数
将成员全都赋值成0了

这样确实很方便,但如果我们想要通过传参的方式来初始化呢?难道就需要自己再创建一个初始化的带参的init函数吗
在这里插入图片描述
那这样的话构造函数用法也太局限了

别忘了,在C++中构造函数是可以进行重载的。

重载

在这里插入图片描述
这样的话,编译器就会自己判断去调用哪个初始化函数了

补充一下:
当我们有了这种传参的构造函数后,当我们创建对象时,不需要传参时:
就会情不自禁写成:
在这里插入图片描述
当我们不需要传参时:
不能用test t1()这样的调用方式,直接test t1即可
因为第一种写法会和函数声明重复,让编译器混淆。

那这里不会产生疑惑吗?

这里已经有两种构造函数了,那他们都算默认构造函数吗?
没错,还真都是

分类

默认构造函数一共有三种
1.用户自己创建的:
i:无参构造函数
ii:缺省构造函数
当用户上面两种任意一个都没实现时

2.编译器会创建一个无参构造函数

这上面三种,都属于默认构造函数

并且只能最多只能存在一个无参构造函数以及最多一个缺省构造函数

使用场景

什么叫使用场景啊?
不是每个类都需要初始化函数吗?
确实是这样,那这个内容就结束了。

那怎么可能呢

还记得这个构造函数是默认成员函数的一部分吗
默认成员函数是指,当用户没有显式实现时,编译器会在类中自己生成的函数。

所以这里的使用场景是指:用户啥时候一定要自己创建构造函数

那这里我们就要知道编译器自己创建的默认构造函数能做到什么程度了
在这里插入图片描述

这里能看到,内置类型的成员变量构造函数不会对它进行处理

对于自定义类型会去调用它的默认构造这句话可能有点难以理解

这里举个例子
在这里插入图片描述
这里我们创建了test类
他的成员变量有一个happy类的对象。
这个时候在我们创建test的对象的时,test中的happy对象就会自己去调用它的默认构造函数。

所以看我们在写test类的时候就不用写默认构造函数
但是happy类是需要写上默认构造函数的:
因为C++规定编译器自动生成的默认构造函数一定要对内置类型进行处理,这个取决于编译器,但是为了代码的可移植性,我们还是要需要写一下

这里就能规划出构造函数的场景了
1.类的成员变量中有内置类型
2.全都是自定义类型成员,就可以考虑让编译器自己生成默认构造函数。

析构函数

这个析构函数,从标题就能知道,构造函数是进行初始化的成员函数
那析构函数就是专门进行清理的成员函数

完成对申请内存的清理。

学了构造函数后,这个析构函数就很简单了。

它不用想,需要被编译器自动调用,肯定也有特殊的命名规则:

在这里插入图片描述

这个命名就是在类名前加一个~这个符号

别问为什么用符号,因为是祖师爷规定的

它同样和构造函数一样没有返回值类型
但是特殊的是它没有参数,毕竟是在程序结束的时候自动调用,也不需要传啥参数

使用场景

这里就注意一个点就行了:
默认生成的析构函数不会对内存进行释放

所以使用场景也就出来了
在这里插入图片描述

第三条是因为自定义类型在他们自己的定义的地方已经写过了(自定义类型最后深究本质也就只是内置类型),程序结束会自己去原类型声明定义的地方里面调用析构函数,和构造函数一样

拷贝赋值

这里的拷贝赋值的作用是针对两个相同类型的类
就是将他们的成员变量进行复制后赋值

拷贝构造函数

看到这个成员的名字,拷贝+构造函数

构造函数是初始化对象的的函数
拷贝,就是复制
加上我们前面说过,这里的拷贝赋值的作用是针对两个相同类型的类

到这里大家应该就知道这个拷贝构造函数是个什么功能了

就是以一个对象的值为参考,来创建一个相同类型的对象

所以它也是属于构造函数,但是
不是默认构造函数!!
不是默认构造函数!!
不是默认构造函数!!
(重复三次显得帅)

拷贝构造函数也是默认函数成员之一
就是说拷贝构造函数的存在,不会阻碍编译器生成默认构造函数

只有之前提到的三种默认构造函数的存在,才会让编译器不会生成默认构造函数,所以这里就可以看出它不是默认构造函数

如果用户没有写,编译器会自己生成一个拷贝构造函数,所以它也是默认成员函数之一

拷贝构造函数的地位和默认构造函数是平等的,但是从属于构造函数

因为拷贝构造函数也属于构造函数,所以也是以构造函数的方式命名

在这里插入图片描述
这里有两个点一个一个看
1.这里加const,是防止对赋值的源变量进行改变。

2.这里传参加了引用
以前博主写过引用的博客
讲了引用可以减少拷贝对象的时间和空间
(可以看作指针的好处,引用的底层实现就是指针)
并且这里引用的对象也不会在这个函数结束后销毁
所以这里使用引用可谓是好处多多。

接下来就是赋值了。

在这里插入图片描述

这里能直接调用的:
_x和_y是this指针调用过来的t2

这里实际的传参是这样的

t2.test(t1)
这里就能看出this指针有多么的好用了

使用场景

这里我们也要来探究当我们没有写拷贝构造时
编译器自动生成的拷贝构造能做到什么程度。

1.内置类型可以通过调用拷贝构造来进行赋值
2.自定义类型(究其本质最后也是内置类型)会调用它的拷贝构造

那这样看,拷贝构造不是无敌了吗?

当然不可能是
不然这样的话为什么还让用户自己来创建,全交给编译器不就好了?

有些特殊情况:

在这里插入图片描述
比如这样创建了一个栈
进行拷贝的时候,创建的两个栈公用一块内存
那不就是乱套了

所以这里我们要引出浅拷贝和深拷贝

浅拷贝与深拷贝

浅拷贝:就是将对象的值完全进行拷贝
深拷贝:将两个对象向内存申请的空间地址分开来,其他值则一样

这里我们也就能知道这个使用场景了

只有在需要深拷贝的时候会自己去写拷贝构造函数,可以说拷贝构造函数就是专门为深拷贝诞生的

赋值重载

以前在日期类的实现中,讲过了复制重载函数的实现
日期类的实现
这里就着重讲一下它和拷贝构造的区别,以及使用场景

赋值重载和拷贝构造函数的区别

赋值重载和拷贝构造函数一样,都属于默认成员函数

当用户没有显式实现时,编译器会自己生成。

并且都是对两个对象的函数,都有赋值的功能,那它们的区别到底在哪?

在这里插入图片描述

赋值重载说到底就是一个运算符,运算符只能对存在的对象使用和接收。
所以赋值运算符只能对两个存在的对象进行操作

而拷贝构造函数都说是构造函数了,所以只需要一个对象,并且创建一个新的对象

那这里来个提问:

Date d4=d2
算是拷贝构造还是赋值重载

其实我们只要把握住核心就行了,赋值重载是对两个已存在的对象
而拷贝构造函数是用一个对象创建并初始化另一个对象

这里Date d4=d2,创建了一个新对象,所以这里本质使用的是拷贝构造函数

使用场景

这里老样子,来探索一下编译器自动生成的复制重载能做到什么程度

当用户没有显式实现的时候,编译器自动生成的默认赋值运算符 ,会对类型的值的逐个字节进行拷贝,自定义类型会调用它们的默认赋值重载,内置类型直接进行赋值

所以这里看的是我们需要的是否为深拷贝

如果是浅拷贝那我们可以用系统自动生成的赋值重载

如果是深拷贝我们就需要自己去编写赋值重载。

取地址重载

取地址是一个操作符,
所以取地址重载同样也属于运算符重载

但是取地址重载因为不像其他默认成员函数那样复杂,
让编译器难以实现。

只需要将该对象的地址取出就可以了
这里只是要遵循,对象使用操作符需要运算符重载

一般其实只用默认成员函数就能够满足要求。
所以这里的实现就不写了(其实也就返回个地址而已)

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

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

相关文章

SpringBoot配置文件 | 多环境配置 | 读取配置的4种方式

文章目录 一、写配置文件的位置读取的优先级:1.文件位置:2.文件名和文件后缀:3.配置文件中的profile-specific文件:4.命令行参数 二、多环境配置1. properties:2. yaml 三、yaml配置文件yaml、properties、xml对比&…

Gateway服务网关入门

Gateway服务网关 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。…

OpenAI ChatGPT Unity接入

OpenAI ChatGPT Unity接入 OpenAI ChatGPT Unity接入OpenAi-API-Unity 方法OpenAi-API-Unity 下载本地配置Unity 模块URL接入gz 接入json 接入Open AIOpenAi-Api-Unity 插件文档 OpenAi 本地化接入 Unity 方法Unity 关键字识别语音合成 & 文字转语音音频记录 & 实时音频…

C语言_数据类型[详细分析]

接上一篇:C语言_关键字_标识符简介 本次来分享C语言的数据类型,是博主的一些学习笔记的和心得的总结,话不多说,开始上菜: 此博主在CSDN发布的文章目录:我的CSDN目录,作为博主在CSDN上发布的文章…

四个PCB工程师最头痛的Allegro问题及解答,你一定要看

Allegro是一款功能强大的PCB设计软件,广泛应用在电子设计行业,在使用Allegro过程中,工程师会遇见到多种复杂的技术问题,本文将针对工程师最头痛的Allegro问题进行回答,希望对小伙伴们有所帮助。 1、如何创建新的Allegr…

线上问题处理案例:出乎意料的数据库连接池 | 京东云技术团队

导读 本文是线上问题处理案例系列之一,旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象,逐步定位到数据库连接池保活问题的全过程,并对其中用到的一些知识点进行了总结。 一、问题描述…

高丰度铈磁体

随着烧结钕铁硼应用领域的不断拓展和产量的快速增长,相应的稀土资源也被大量开采。稀土矿中各种稀土元素是共生的,但在钕铁硼的制备过程中,利用的主要是在轻稀土中质量分数为25%的镨Pr和钕Nd元素,这样对轻稀土中占比为质量分数49%…

AIGC周报|让AI来画《海贼王》;苹果限制员工使用ChatGPT;李彦宏:不担心大模型会让工作消失

AIGC(AI Generated Content)即人工智能生成内容。近期爆火的 AI 聊天机器人 ChatGPT,以及 DallE 2、Stable Diffusion 等文生图模型,都属于 AIGC 的典型案例,它们通过借鉴现有的、人类创造的内容来快速完成内容创作。 …

MySQL备份

MySQL的备份方式有哪几种?分别如何实现? 目录 一、数据的备份类型 1、数据的备份类型根据其自身的特性主要分为以下几组: 二、MySQL备份数据的方式 三、常见的备份工具 1、一般情况下, 我们需要备份的数据分为以下几种 2、备份工具 3…

SpringBoot—常用注解

目录 一、注解(annotations)列表 二、注解(annotations)详解 三、JPA注解 四、springMVC相关注解 五、全局异常处理 一、注解(annotations)列表 SpringBootApplication: 包含了ComponentScan、Configuration和EnableAutoConfiguration注解。其中ComponentScan…

【大学物理实验】基本测量

50分度的游标卡尺,最小分度为: A. 0.1mm B. 0.2mm C. 0.5mm D. 0.02mm 正确答案: D 保存游标卡尺和螺旋测微器是,下面说法正确的是: A. 游标卡尺测量位置应闭合,螺旋测微器小砧和螺杆间隙也应闭合 B. 游标…

Matlab论文插图绘制模板第94期—带置信区间的折线散点图

在之前的文章中,分享了很多Matlab带置信区间的折线图的绘制模板: 进一步,再来分享一下带置信区间的折线散点图的绘制模板。 先来看一下成品效果: 特别提示:本期内容『数据代码』已上传资源群中,加群的朋友…

SSD202 Linux开发日志记录

一、挂载U盘 SDK默认自动加载USB存储模块,但没有自动挂载,插上U盘后识别sda mount /dev/sda /mnt/即可在/mnt查看U盘文件 二、make & make menuconfig提示失败 打开新终端后输入 declare -x ARCH"arm" declare -x CROSS_COMPILE"…

机器学习中四类进化算法的详解(遗传算法、差分进化算法、协同进化算法、分布估计算法)

1、遗传算法(Genetic Algorithm,GA) GA算法原理 首先我们来介绍进化算法的先驱遗传算法,遗传算法(Genetic Algorithm,简称GA)是一种最基本的进化算法,它是模拟达尔文生物进化理论的…

企业级WordPress开发 – 创建企业级网站的优秀提示

目录 “企业级”是什么意思? 使用WordPress创建企业级网站有什么好处? 使用 WordPress 进行企业开发的主要好处 WordPress 可扩展、灵活且价格合理 WordPress 提供响应式 Web 开发 WordPress 提供了巨大的可扩展性 不断更新使 WordPress 万无一…

Nodejs模块化

介绍 将一个复杂的程序文件按照一定规则拆分成多个文件。 拆分出的每个文件就是一个模块,模块的内容数据是私有的,不过模块可以暴露内部数据使得其他模块使用。 模块化好处:防止命名冲突、高复用性、高维护性。 模块化的使用 初体验 两…

云计算基础——云计算与移动互联网、物联网

8.1 云计算与移动互联网 8.1.1 移动互联网的发展概况 移动互联网的发展概况 移动互联网是指以宽带IP为技术核心,可同时提供语音、数据、多媒体等业务服务的开什么是移动互联网?放式基础电信网络,从用户行为角度来看,移动互联网广义上是指用…

Linux下的用户分类与su/sudo 命令,Linux下的文件类型/用户文件权限身份/文件权限属性/权限与文件权限/ls-l文件属性详解

Tips 下载就是把我们的文件拷贝到系统的某个特定路径之下,普通用户是不允许你往系统里面去拷的。 Linux下的用户分类 root用户,管理员级别的用户身份,他的话基本上不受权限的约束。普通用户,普通用户的添加与每个普通用户密码的…

8.防火墙-SNAT和DNAT

文章目录 SNAT-内网客户访问外网服务原理操作实验 DNAT-外网客户访问内网服务原理操作实验 tcpdump SNAT-内网客户访问外网服务 原理 由内网到外网:从内网发到外网的数据包的源IP由私网IP转换成公网IP 由外网到内网:从外网发到内网的数据包的目的IP由公…

学系统集成项目管理工程师(中项)系列24a_信息系统集成专业技术知识(上)

1. 信息系统的生命周期 1.1. 【19下选10】 1.2. 立项 1.2.1. 形成《需求规格说明书》并确定立项 1.2.1.1. 【21上选11】 1.3. 开发 1.3.1. 【22下选10】 1.3.2. 以立项阶段所做的需求分析为基础,进行总体规划。之后,通过系统分析、系统设计、系统…
最新文章