【C++笔记】C++之类与对象(中)

news2024/9/18 10:43:32

【C++笔记】C++之类与对象(中)

  • 1、类的构造函数
    • 1.1、构造函数的基本用法
    • 1.2、构造函数的7个特性
  • 2、类的析构函数
    • 2.1、析构函数的基本用法
    • 2.2、析构函数的6个特性
  • 3、类的拷贝构造函数
    • 3.1、拷贝构造的基本用法
    • 3.2、拷贝构造的“无限套娃”陷阱
    • 3.3、深拷贝与浅拷贝
  • 4、运算符重载
    • 4.1、运算符重载的基本使用方法
    • 4.2、运算符重载使用的注意事项
    • 4.3、重载前置++和后置++怎么区分?
  • 5、类的const成员函数

1、类的构造函数

其实每个类都有6个默认成员函数:
在这里插入图片描述
默认成员函数指的是:用户没有显示实现编译器会自动生成的函数。
这些函数主要完成一些初始化和资源回收和复制的工作,而且有些有些是会自动调用的。有了这些成员函数,我们的类使用起来就能更省心。
而我们这个阶段只会接触到前两个“初始化和清理”和“拷贝构造”。

第一个默认成员函数就是构造函数,它主要完成的是对类的初始化工作。

1.1、构造函数的基本用法

其实构造函数,就和我们以前写的初始化函数一样,只不过构造函数更方便一些,在写法上他有两个特征:
在这里插入图片描述
然后函数体内的写法就和以前的初始化函数差不多。
就拿栈这个类来举例,我们就可以这样来写构造函数:
在这里插入图片描述
当然了,构造函数也是可以传参的,我们可以传一个参数表示要开多少空间:
在这里插入图片描述
而它的用法就是在创建类对象的时候,在类对象后面加一个括号,括号后面加上对应的参数即可:
在这里插入图片描述
而构造函数是自动调用的,为了验证这个特点,我们可以把构造函数改成无参的:
在这里插入图片描述

1.2、构造函数的7个特性

其实构造函数,难就难在特性太多了,不好记,构造函数总的有7个特性,前面是个是:

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。

前三个我们已经验证过了,我们就从第4个开始逐一验证。

4. 构造函数可以重载。

既然C++搞出了函数重载,那为什么构造函数就不能重重载呢?而且构造函数的重载为我们提供了更多的初始化方法,例如对于栈这个类,我们就可以写这样的两个构造函数,这样在初始化的时候就可以有两种初始化的方式可以选择了:
在这里插入图片描述

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

验证个这个特性我们就只需要保留一个有参数的构造函数,再使用不传参初始化的方式即可:
在这里插入图片描述
而要是我们不主动去写构造函数,编译器就不会报错了:
在这里插入图片描述

6.编译器生成的默认构造函数对内置类型不进行处理,对自定义类型就调用其默认构造函数。

我们可以通过调试来看一看上面的例子中的,个成员有没有被处理:
在这里插入图片描述
我们可以看到,所有的成员都还只是随机值,因为这里的所有成员都是内置类型的。

我们可以再随便定义一个自定义类型,来验证第二点:
在这里插入图片描述

7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为
是默认构造函数。

构造函数麻烦就麻烦在这里,我们大概率都会认为编译器自动生成的无参的构造函数就是默认构造函数,但是它偏不是,而是有三个。

而我们只需要证明全缺省的构造函数是默认构造函数即可:
在这里插入图片描述
其实构造函数可以简单理解为,不用传参就可以调用的函数,所以全缺省的构造函数也是一个默认构造函数。

但要是我们不提供默认构造函数,而只是写了一个不符合默认构造函数的构造函数,如果我们在初始化的时候以不传参的方式初始化,编译器就会报错,因为找不到默认构造函数:
在这里插入图片描述
这是因为一旦我们显示的写了构造函数,那不管其满不满足默认构造函数的条件,编译器都不会在生成默认的构造函数了。

2、类的析构函数

析构函数其实就类似于我们以前写的销毁函数destroy,它的主要工作就是,清理数据和释放空间。

2.1、析构函数的基本用法

析构函数在语法上有两个特点:
在这里插入图片描述
还是拿栈来举例,栈的析构函数可以这样写:
在这里插入图片描述
注意:析构函数不能显示调用!

2.2、析构函数的6个特性

与构造函数一样,析构函数也有一些让人头晕的特性,前面两个:
在这里插入图片描述
我们已经清楚。

那我们从第三个开始说起。

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载

也就是说析构函数不能重载:
在这里插入图片描述
至于编译器自动生成的析构函数,我不会验证,反正记住就行了。

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

这一条上面已经验证过了。

5.编译器自动生成的析构函数对于内置类型不作处理,对于自定义类型则去调用其析构函数。

置于为什么对于内置类型不作处理,我想应该很容易理解,因为内置类型本身出了作用域就会随着内存一并被回收,所以处不处理都一样了。

而关于第二点,我们可以用以下例子来证明:
在这里插入图片描述

  1. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如
    Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

3、类的拷贝构造函数

就像内置类型总是需要将一个变量的数据拷贝给另一个变量一样,自定义类型也需要将一个对象的数据拷贝给另个一对象,这就需要我们的拷贝构造了。

3.1、拷贝构造的基本用法

拷贝构造其实是构造函数的一个重载样式,所以它的函数名也是也类名相同,并且拷贝构造规定只有一个参数,就是一个同类型的引用。
就拿日期类来举例,日期类的拷贝构造就可以这样写:
在这里插入图片描述
然后调用其实也是向初始化一样,只不过参数变成了另一个对象:
在这里插入图片描述

3.2、拷贝构造的“无限套娃”陷阱

为什么拷贝构造一定要传一个对象的引用,那直接穿一个对象行不行呢?
其实,C++规定,如果函数传参传的是一个类对象,那么在函数调用的第一步传参的时候,就要去调用这个类的拷贝构造去生成一个拷贝。
我们可以通过以下例子来验证:
在这里插入图片描述
我们可以看到,这里只是简单地调用了一下func(),而函数内并没有做任何操作,却已经调用了拷贝构造。从而我们就可以确认类的传值传参就回去调用拷贝构造。

这样我们就可就可以来解释为什么,拷贝构造规定只能传对象的引用了,如果我们拷贝构造传是对象的值拷贝,那么在调用拷贝构造之前就会先去调用拷贝构造,而调用拷贝构造就需要传值,那就会再去调用拷贝构造,如此循环往复无穷无尽。所以如果拷贝构造传的是类对象的只拷贝就会陷入这样的一一个死循环:
在这里插入图片描述
而我这里的编译器是进行了强制检查的。

3.3、深拷贝与浅拷贝

其他的构造函数都有编译器自动生成的版本,拷贝构造也有,但编译器自动生成的拷贝构造完成的是“浅拷贝”,而浅拷贝存在一些问题,这个问题我们可以通过下面这个例子看出:
在这里插入图片描述
可以看出,对于栈这个类只进行浅拷贝的话就崩了。而且我们看到调用了两次析构函数。
这是因为:

编译器自动生成的拷贝构造对内置类型会进行值拷贝,而对于自定义类型会去调用其拷贝构造。

而现在写的栈的所有成员都是内置类型,那就是只进行值拷贝了,这里的问题出就出在析构函数。因为成员函数都只进行了值拷贝,所以两个栈对象的_data都指向了同一块空间。而而当其中一个栈析构了以后,这一块空间就已经被释放了,然后后一个栈又调用了一次析构函数,这就会导致同一块空间被释放了两次,这就是报错的原因。

所以对于栈这种有额外空间申请的类,我们应该进行的是“深拷贝”:
在这里插入图片描述

4、运算符重载

有时候我们也需要将各个类对象进行比较,但我们不能直接运用运算符进行比较,因为只有内置类型才能这样做。因为编译器并不知道你自己定义的类型到底该怎样比较。
这就需要运算符重载出场了。

4.1、运算符重载的基本使用方法

运算符重载的函数名就是“operator”加上各种运算符,而返回值可以是布尔类型或其他各个类型。
比如我们要比较两个日期类对对象那个更小,就可以这样写:
在这里插入图片描述
这样我们就可以直接使用小于运算符比较两个类对象了:
在这里插入图片描述
而这里之所以要加上括号的原因是,流插入的优先级要高于小于运算符,如果不加上的话就会报错了:
在这里插入图片描述

4.2、运算符重载使用的注意事项

运算符重载的使用也有一些注意事项。

1.不能通过连接其他符号来创建新的操作符:比如operator@

当然,我们不能自己创造运算符,我们重载的运算符必须是C++已有的运算符,例如:
在这里插入图片描述

2.重载操作符必须有一个同类类型参数

这个必须有的同类型参数就是我们的this,因为对象调用的时候一定要将自己的指针传过去,只不过这个this指针是隐藏起来的。

剩下的三点分别是:

3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
4.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
5.".* :: sizeof ?: . "注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

4.3、重载前置++和后置++怎么区分?

对于函数名相同且,不用传参数的运算符重载的函数,我们该怎么区分呢?
例如这里的前置++和后置++。
我们可以为其中一个添加一个额外的“无用”的参数:
在这里插入图片描述
这样便一起在调用的时候就可以看情况,是否要加上一个参数来区分了。
当然,这个参数你传任何值都是一样的,因为它的存在只是为了做一个区分,本身不是用来使用的。.

5、类的const成员函数

因为在引用的过程中,权限不能放大,所以对于const对象有些函数是不能调用的:
在这里插入图片描述
因为引用的底层其实就是用指针实现的,所以这里可以将引用等同于指针。因为Print隐藏的this指针不是const的,所以这里的调用实则是将const的指针转化成了非const指针,涉及到了权限的放大。
为了决绝这个问题,我们可以添加一个const修饰的Print函数:
在这里插入图片描述
const函数的语法就是在函数的后面加上一个const。
这里的const和非const的函数其实是构成了重载。
这样便一起在调用的时候就会自动去匹配最符合的函数,const的对象就去调用const的Print函数,非const对象就会去调用非const的Print函数。

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

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

相关文章

汽车领域专业术语

1. DMS/OMS/RMS/IMS DMS:即Driver Monitoring System,监测对象为Driver(驾驶员)。DMS三大核心: OMS:即Occupancy Monitoring System,监测对象为乘客。 RMS:后排盲区检测系统 IMS&…

动手学深度学习--基础知识上篇

🎈动手学deep learning ☁️本专栏会定期更新关于动手学深度学习的每章知识点的讲解,题目答案 👻如果喜欢,欢迎点赞,收藏 动手学深度学习-预备知识篇 线性代数篇 1-3题讲解 证明一个矩阵 A \mathbf{A} A的转置的转置…

C#程序配置读写例子 - 开源研究系列文章

今天讲讲关于C#的配置文件读写的例子。 对于应用程序的配置文件,以前都是用的ini文件进行读写的,这个与现在的json类似,都是键值对应的,这次介绍的是基于XML的序列化和反序列化的读写例子。对于ini文件,操作系统已经提…

Java课题笔记~ 整合第三方技术

1. 整合JUnit 问题导入 回忆一下Spring整合JUnit的步骤&#xff1f; 1.1 Spring整合JUnit&#xff08;复习&#xff09; 1.2 SpringBoot整合JUnit 【第一步】添加整合junit起步依赖(可以直接勾选) <dependency><groupId>org.springframework.boot</groupId…

什么是变量提升(hoisting)?它在JavaScript中是如何工作的?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 变量提升&#xff08;Hoisting&#xff09;⭐ 变量提升的示例&#xff1a;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

水果成篮(力扣)双指针滑动窗口 JAVA

你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示&#xff0c;其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而&#xff0c;农场的主人设定了一些严格的规矩&#xff0c;你必须按照要求采摘水果&…

[管理与领导-27]:IT基层管理者 - 团队管理 - 育人 - 如何评估团队的能力?如何培养团队?

目录 一. 培养团队&#xff08;练兵&#xff09;为什么很重要 二. 如何评估团队的能力模型 三、培养人才 一. 培养团队&#xff08;练兵&#xff09;为什么很重要 培养团队是组织中的一项重要任务&#xff0c;以下是一些说明为什么培养团队是如此重要的原因&#xff1a; 养…

MAC QT开发攻略

文章目录 基础步骤安装QT、QTCreator安装CMakeNinja 安装Clion编译器在QTCreator中新建项目更改CMake生成器 导入Clion CMake生成文件 基础步骤 安装QT、QTCreator 安装CMake 由于clion需要使用cmake构建 Ninja Ninja下载 安装Clion编译器 Clion 2023.1.3 破解版安装教程…

从零注册和搭建搭建uniapp微信小程序项目

03 - 开发环境搭建和项目创建 语雀 目标 什么是小程序拥有小程序开发者账号安装微信开发者工具创建小程序项目使用基本的组件上线一个体验版小程序 什么是小程序 了解小程序&#xff0c;以及小程序开发为什么会成为一门单独的职业。 我们从以下3个视角&#xff0c;来了解一下…

手把手教学——终端工具xshell与文件传输工具xftp使用步骤及详解

前言 xshell是一款常用于连接本地linux服务以及云服务器的终端远程连接工具&#xff0c;该款终端工具常搭配远程文件传输工具xftp一起使用&#xff0c;由于还有很多小伙伴还不知道这两款终端工具的使用流程及步骤&#xff0c;Darren洋在这里给小伙伴们进行详细讲解。 一、下载工…

【Java】对象数组排序(Comparable接口/Comparator接口)

Comparable接口&#xff08;compareTo&#xff09; Arrays 类中的 sort 方法承诺可以对对象数组进行排序&#xff0c;但要求满足下列前提&#xff1a;对象所属的类必须实现了 Comparable 接口&#xff0c;且定义了compareTo方法。 Comparable接口的代码 public interface Comp…

无涯教程-TensorFlow - 单词嵌入

Word embedding是从离散对象(如单词)映射到向量和实数的概念&#xff0c;可将离散的输入对象有效地转换为有用的向量。 Word embedding的输入如下所示: blue: (0.01359, 0.00075997, 0.24608, ..., -0.2524, 1.0048, 0.06259) blues: (0.01396, 0.11887, -0.48963, ..., 0.03…

解决Pycharm的Settings中Project不见了也无法选择Python Interpreter的方法

目录 一、问题如下二、解决方法 一、问题如下 突然打开项目没有python解释器&#xff0c;也无法重新配置python Interpreter&#xff0c;而且整个文件夹是黄色高亮的形式&#xff0c;如下显示&#xff0c;而且重新安装了pycharm也没用甚至说打开File–>Setting–>Projec…

网络编程套接字(1)

文章目录 网络编程套接字(1)1. 预备知识1.1 源IP与目的IP1.2 认识端口号1.3 理解 "端口号" 和 "进程ID"1.4 源端口号和目的端口号1.5 认识TCP协议和UDP协议(1) TCP(2) UDP 1.6 网络字节序 2. socket编程接口2.1 socket 常见API2.2 sockaddr结构 网络编程套…

深度学习环境搭建 cuda、模型量化bitsandbytes安装教程 windows、linux

cuda、cudann、conda安装教程 输入以下命令&#xff0c;查看 GPU 支持的最高 CUDA 版本。 nvidia-smi cuda安装&#xff08;cudatoolkit&#xff09; 前往 Nvidia 的 CUDA 官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer CUDA Toolkit 11.8 Downloads | NVIDIA …

react之路由的安装与使用

一、路由安装 路由官网2021.11月初&#xff0c;react-router 更新到 v6 版本。使用最广泛的 v5 版本的使用 npm i react-router-dom5.3.0二、路由使用 2.1 路由的简单使用 第一步 在根目录下 创建 views 文件夹 ,用于放置路由页面 films.js示例代码 export default functio…

IDM最新版2023不限速下载网盘详细操作教程

开启这个开关&#xff0c;让你的浏览器下载速度翻倍!大家有没有听说过IDM下载器&#xff0c;那是因为它的多线程下载功能&#xff0c;所以下载速度快&#xff0c;其实我们的浏览器也有多线程下载功能&#xff0c;只是默认关闭了而已&#xff0c;只需开启它&#xff0c;就可以有…

商城-学习整理-高级-性能压测缓存问题(十一)

目录 一、基本介绍1、性能指标2、JMeter1、JMeter 安装2、JMeter 压测示例1、添加线程组2、添加 HTTP 请求3、添加监听器4、启动压测&查看分析结果 3、JMeter Address Already in use 错误解决 二、性能监控1、jvm 内存模型2、堆3、jconsole 与 jvisualvm1、jvisualvm 能干…

sd-webui安装comfyui扩展

文章目录 导读ComfyUI 环境安装1. 安装相关组件2. 启动sd-webui3. 访问sd-webui 错误信息以及解决办法 导读 这篇文章主要给大家介绍如何在sd-webui中来安装ComfyUI插件 ComfyUI ComfyUI是一个基于节点流程式的stable diffusion的绘图工具&#xff0c;它集成了stable diffus…

第8章:集成学习

个体与集成 同质&#xff1a;相同的基学习器&#xff0c;实现容易&#xff0c;但是很难保证差异性。异质&#xff1a;不同的基学习器&#xff0c;实现复杂&#xff0c;不同模型之间本来就存在差异性&#xff0c;但是很难直接比较不同模型的输出&#xff0c;需要复杂的配准方法。…