深入学习默认成员函数——c++指南
前言:类和对象是面向对象语言的重要概念。 c++身为一门既面向过程,又面向对象的语言。 想要学习c++, 首先同样要先了解类和对象。 本节就类和对象的几种构造函数相关内容进行深入的解析。
目录
类和对象的基本概念
封装
类域和类体
访问限定符
private
public
protect
默认访问限定
成员函数与this指针
构造函数
初始化规则
三个必须初始化的变量类型
默认构造函数
默认成员函数
默认构造函数
默认拷贝构造函数
拷贝构造
默认拷贝构造
析构函数
析构函数
默认析构函数
类和对象的基本概念
类是一种抽象的数据类型。它规定了某种事物的特征(成员变量,可以理解为一种属性,是静态的)和行为(成员函数,可以理解为动作,是动态的)。和c语言结构体类似, 类可以看作这种事物的模板或者蓝图。
对象则是类的具体实例,是具体的。拥有着类规定的特征和行为。 我们都知道, 一个蓝图可以创造许多建筑。 那么一个类也可以创建多个对象。并且每个对象都有着类似的特征和行为。
如图就是定义的一个类,这个类规定了事物stu有三个特征:姓名, 学号, 成绩。 有着一个行为:修改成绩。并且将其实例化出对象p1, 此时p1有着这个类规定的三个特征,一个行为—— p1有着自己的名字, 有着自己的学号, 有着自己的成绩。 同时他还能修改自己的成绩。
(注:c++的小语法相对于c语言多了许多,虽然使用方便,但是刚开始学c++也可能很难全部掌握,所以建议刚开始学习c++的时候建议勤看看小的知识点。比如c向c++过渡的一些知识点。这样学着会舒服很多, 不会有一种模糊的感觉。比如图中的成员函数的知识点就是缺省参数,这同样是c向c++过渡的一些小知识点。 但是掌握不熟悉就会迷惑。不要不信,比如我问你半缺省(int x = 10, int y )这样是否正确,你根据你心里的答案, 然后拟定传参(1), 你看看是否正确?这个1是给谁?如果你很懵, 那你可以在看完这篇文章后去复习它。恭喜你对这个知识点又加深了一点理解。 )
封装
类和对象三大特征:封装, 继承和多态,这里讲解封装, 继承和多态后续再说。
首先, 封装的概念很好理解, 就是将一个或多个特征属性和一个或多个行为方法封装起来。只对外公布接口。使用人通过接口操作修改对象的属性。 封装有利于数据的安全性和完整性。同时有利于代码的模块化和可维护。
图中的student类封装起来了三个特征变量:name, num, grade。 一个接口函数revise_grade:
图中private, public是访问限定符, 决定了类的实例是否可以直接调用类的成员。
类域和类体
类域和类体是类和对象的两个重要组成部分。
类域是指类的属性和特性, 也就是类的成员变量。 类域可以是公共的(public),私有的(private)或受保护的(protected)。公共的类域可以被类的外部访问,私有的类域只能在类内部本地访问。受保护的类域这里不解释, 可以看作和私有的类域相同。
类体是指包含在类声明中的代码块,它定义了类的行为和功能。类体包含了构造函数、成员函数、成员变量,以及其他相关代码。也就是说类体包含类域。
访问限定符
访问限定符有三个: private, public, protect.
private
private的意思的私有, 在private以下定义的成员不能被类的实例直接访问到。 只能通过成员函数间接访问。

这里可以利用成员函数revise_grade间接访问

public
public的意思是公有, public之后定义的成员可以被类的实例访问。

protect
protect和private类似, 在他们之后定义的成员都不可直接访问。
默认访问限定
访问限定符的范围是该访问限定符到下一个访问限定符的中间的内容。如果下面没有访问限定符, 那么就是之后的所有范围。

struct的默认访问限定是public;
class的默认访问限定是private。
这些记住就行。
成员函数与this指针
要理解封装的概念, 还要理解this指针在类中起到的作用。
类中的成员函数默认第一个形参都是this指针, this指针是一个关键词,并且这个this指针调用该函数的对象。我们平常定义构造函数或者成员函数是看不到定义this指针知识将this指针隐藏了。

this指针可以让我们找到特定的对象。
构造函数
构造函数是类和对象中新添的一种概念。类在进行实例化时会自动调用自己的构造函数。
如图红框框就是定义的一个构造函数,构造函数的定义实现方式与普通函数有两处不同:
1.构造函数没有返回值。
2.构造函数有符号化列表,也就是图中的绿框框。
符号化列表的初始化使用括号的方式, 括号中就是初始化的数值。这里三个变量分别是_name, _num, _grade, 然后通过形参name, num, grade对他们进行赋值。
初始化规则
下面请仔细阅读。很复杂,很重要。
首先, 构造函数的执行方式顺序是先初始化列表。再函数体。
然后,初始化列表的执行顺序不是从上到下, 而是按照成员变量的声明顺序进行初始化。
初始化列表中没有初始化的对象, 比如_name, 就只能等到函数体再初始化。
初始化列表对内置类型就是如图中的初始化方式。注意, 是内置类型才是上面的方式。自定义类型就没有这么简单了。
首先构造函数的执行顺序不会改变。 但是如果成员变量中有自定义类型的话, 它在初始化的时候, 会去调用自己相应的构造函数。 (因为对内置类型编译器可以直接进行赋值拷贝工作。但是对于自定义类型, 编译器无法自己进行复制拷贝工作。 所以只能去调用类型本身的构造函数。 这其实就是套娃的过程:如果调用的构造函数中还有自定义类型的初始化, 那么就要再去调用那个自定义类型的构造函数,直到调用的构造函数中没有自定义类型 )
-------------------------------------------------------------------------------------------------------------------------
以上, 是将自定义类型显示在符号化列表初始化的情况。 如果没有在符号化列表初始化的话。 那么编译器会自动对该自定义类型变量进行初始化。并且初始化时不传参,就是这个意思
就相当于这里的_b进行初始化的时候没有传参。
以上, 就是初始化列表对于自定义类型以及内置类型初始化的规则。
现在引入两个概念, 一个概念是:三种必须在初始化列表初始化的变量类型。
第二个概念是:默认构造函数的概念。
三个必须初始化的变量类型
三个必须在初始化列表初始化的变量类型:引用类型, const修饰的常变量, 以及上面讲的自定义类型。
那么为什么会有这样的规定?
首先引用类型必须在定义的时候初始化。类的实例化的同时也是对类的特征,属性进行初始化的时候。如果这一次没有初始化。 那么之后再对类的特征进行处理, 那不是初始化。 那叫赋值。
所以必须对引用类型进行初始化。
至于const修饰的常变量同样的道理, 因为必须在定义的时候初始化, 那么就必须在初始化列表初始化。 你可能有疑惑说为什么必须在初始化列表, 在构造函数的函数体初始化不行吗?其实, c++中规定了, 初始化列表的叫初始化, 函数体中的是赋值。
-----------------------------------------------自定义类型很重要--------------------------------------------------
自定义类型为什么规定不做解释, 只需要知道这样规定就好。重点是自定义类型与上面两个有点差异。 虽然自定义类型也必须初始化。 但是如果我们不对它进行初始化, 编译器不会报错。 而是自己去调用自定义类型的默认构造函数。 这就叫自定义类型的隐式初始化。
-------------------------------------------------------------------------------------------------------------------------
默认构造函数
那么什么是默认构造函数, 这就是我们的第二个要引入的概念:
默认构造函数就是:没有形参, 或者形参全缺省的构造函数。
默认成员函数
在c++的类的成员函数中,有六个特殊的成员函数, 被称为默认成员函数。
默认成员函数的意思就是如果不定义他们, 系统就会自动生成。
这里主要分析三个:默认构造函数
默认拷贝构造函数
析构函数
默认构造函数
首先, 什么是默认构造函数,这个概念在上面我们刚刚提到。 这里不做赘述。
那么编译器生成的默认构造函数什么样的?如图:

如图中红框框,编译器就会默认生程这样的默认构造函数。
由此我们可以知道。 这里生成的默认构造函数虽然是个空函数体, 空初始化列表。 但是通过上面的知识我们直到。 他会对自定义类型进行处理——自定义类型的隐式初始化。
所以:默认构造函数的作用是对内置类型不做任何处理。 但是对于自定义类型会去调用它的默认构造函数。
如果我们定义了任意一个构造函数, 编译器都不会生成默认构造函数。

这个时候我们如果这样定义, 就会报错, 因为没有可以调用的构造函数。
但是我们如果不定义这个构造函数, 就可以编译通过, 因为此时编译器默认生成了一个空的默认构造函数, 不需要传参。 可以匹配p1
有一个好办法就是定义全缺省的默认构造函数, 这样就可以一劳永逸, 不必担心传参是否有匹配的构造函数的问题:
默认拷贝构造函数
在学习默认拷贝构造函数之前我们要先学习拷贝构造函数
拷贝构造
拷贝构造是构造函数的一种重载形式。 它的参数是类本身实例化对象。意思就是将已经实例化的对象的值拷贝给将要实例化的对象。

当我们使用对象初始化对象的时候就会调用拷贝构造。
默认拷贝构造
默认拷贝构造只对内置类型进行浅拷贝操作。如果是涉及到动态分配问题。那么就达不到我们的要求。 因为编译器不会对动态内存分配的内存里的数据进行拷贝。

像图中, 只是p1的_name成员保存的地址赋值给了p2的_name成员。

但是, 这不符合我们的要求。 所以我们就不能使用默认拷贝构造函数。 而是需要我们自己定义拷贝构造函数。


像如图中自己定义的拷贝构造就是深拷贝。
析构函数
拷贝构造一样, 在学习默认析构函数之前我们应该了解以下析构函数。
析构函数
析构函数就是对空间进行释放。 对于内置类型来说, 不需要定义析构函数, 因为编译器会自动对内置类型进行释放。 但是涉及到资源分配的问题。 编译器无法直接对资源分配空间进行释放。 所以就用到了析构函数。
析构函数的函数名称是类名前面加上~, 并且析构函数不接受任何传参。 同时析构函数最多只能有一个。
默认析构函数
编译器默认生成的析构函数就是默认构造函数。 默认构造函数的类体是空。对于内置类型不做处理, 对于自定义类型会去调用该自定义类型的构造函数。
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数即可;但是有资源申请时,否则会造成资源泄漏。
如何区分改写不该写呢?其实, 只要你自己定义了拷贝构造函数的时候, 就要自己手动定义析构函数。 因为只要你自己的定义了拷贝构造, 说明就涉及到了深拷贝问题。 深拷贝就是内存资源分配的问题。 就要定义析构。
以上就是本节的全部内容。
相关文章:
深入学习默认成员函数——c++指南
前言:类和对象是面向对象语言的重要概念。 c身为一门既面向过程,又面向对象的语言。 想要学习c, 首先同样要先了解类和对象。 本节就类和对象的几种构造函数相关内容进行深入的解析。 目录 类和对象的基本概念 封装 类域和类体 访问限定符…...
psutil, 一个超级有用的Python库
Python的psutil是一个跨平台的库,可以用于获取系统运行时的各种信息,包括CPU使用率、内存使用情况、磁盘和网络信息等。它主要用来做系统监控,性能分析,进程管理。它实现了同等命令行工具提供的功能,如ps、top、lsof、…...
[Python]`threading.local`创建线程本地数据
在Python中,threading.local是一个用于创建线程本地数据的工具。它允许每个线程拥有自己独立的变量副本,这样可以在多线程程序中避免共享变量带来的问题。 通过使用threading.local,你可以为每个线程创建一个独立的变量空间,这样…...
删除数据表
oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 删除数据表属于数据库对象的操作 drop table 表名称; 删除 emp30 表 SQL> drop table emp30;表已删除。 上面这个语句运行后,就会把数据表 emp30 删除 在…...
前端自带的base64转化方法
前端html的base64使用方法window.btoa()和window.atob()_html用window.btoa();-CSDN博客...
图论(二)之最短路问题
最短路 Dijkstra求最短路 文章目录 最短路Dijkstra求最短路栗题思想题目代码代码如下bellman-ford算法分析只能用bellman-ford来解决的题型题目完整代码 spfa求最短路spfa 算法思路明确一下松弛的概念。spfa算法文字说明:spfa 图解: 题目完整代码总结ti…...
.NET Core 日志记录功能详解
在软件开发和运维过程中,日志记录是一个非常重要的功能。它可以帮助开发者跟踪应用程序的运行状况、诊断和监控问题。.NET Core 提供了一个灵活且易于使用的日志系统,本文将详细介绍.NET Core日志的相关概念、配置和使用方法。 1. 什么是日志记录以及它…...
docker——启动各种服务
1.Mysql 2.Redis 3.nginx 4.ES 注意:ES7之后环境为 -e ELASTICSEARCH_HOSTS http://ip地址:9200...
git远程仓库使用
赋值这个地址clone 克隆之后 cd slam_oncloud/ git remote add chenxnew ssh://git192.168.3.40:1022/chenxiao/slam_oncloud.git 查看一下 linuxchenxiao:/media/linux/mydisk/cloud_slam/slam_oncloud$ git remote add chenxnew ssh://git192.168.3.40:1022/chenxiao/sla…...
js导出的excel文件无法打开/打开乱码,excel无法打开xxx.xlsx因为文件格式或文件扩展无效
excel无法打开xxx.xlsx因为文件格式或文件扩展无效 使用 a 标签导出这里就不细说了,直接说上述问题解决方案 在调用导出接口的时候加上两个参数 responseType: “blob” responseEncoding: “utf8” export function test(data) {return util({url: /test,method: …...
透明多级分流系统(用户端缓存和负载均衡)
部件考虑 有些设备位于客户端或者网络边缘,能够迅速响应用户请求,避免给cpu和数据库带来压力,比如,本地缓存,内容分发网络,反向代理等。 有些设备处理能力能够线性扩展,易于伸缩,应…...
Python sort从大到小排序面试题
在Python中,你可以使用内置的sorted()函数或者列表的sort()方法来对列表中的元素进行从大到小的排序。 使用sorted()函数: numbers [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] sorted_numbers sorted(numbers, reverseTrue) # 设置reverseTrue实现从大到小排…...
【Stable Diffusion】入门:AI绘画提示词+参数设置攻略
目录 1 提示词1.1 分类和书写方式1.1.1 内容型提示词1.1.2 标准化提示词1.1.3 通用模板 1.2 权重1.2.1 套括号1.2.2 数字权重1.2.3 进阶语法 1.3 负面提示词 2 参数详解2.1 Sampling steps2.2 Sampling method2.3 Width, Height2.4 CFG Scale2.5 Seed2.6 Batch count, Batch si…...
Qt使用Q_DECLARE_INTERFACE Q_INTERFACES宏实现接口类使用qobject_cast进行类型转换
在写抽象类或者接口的时候,肯定是不能继承QObject的 但是又想使用qobject_cast进行类型转换,使用以下办法就能实现 #ifndef FACTORYINTERFACE_H__ #define FACTORYINTERFACE_H__ #include <QObject> class FactoryInterface{ public:FactoryInterf…...
docker离线搭建仓库
要在Docker中搭建本地仓库,可以按照以下步骤进行操作: 首先安装 Docker。根据不同的操作系统选择合适的版本并完成安装过程。打开命令行工具(如Terminal或PowerShell),运行以下命令来创建一个新的容器并将其设置为本地…...
ABC344 A-E题解
文章目录 A题目AC Code: B题目AC Code: C题目AC Code: D题目AC Code: E题目AC Code: 不易不难,写到5题很简单,但是要有足够的思维能力。 A 题目 我们用一个 flag 变量记录我们是不是在两个竖…...
Jeecg-boot 初次启动项目失败
1.将IDEA的字符编码全部改成utf-8 2. 更改database的密码 3.换个jdk重新启动...
封装的echarts子组件使用watch监听option失效的问题
项目场景: 我在项目里面封装了一个echarts组件,组件接收一个来自外部的option,然后我用了一个watch函数去监听这个option的变化,option变化之后,销毁,然后再新建一个charts表 碎碎念 问题如标题所示,这篇…...
爬虫入门到精通_框架篇14(PySpider架构概述及用法详解)
官方文档 Sample Code: from pyspider.libs.base_handler import *class Handler(BaseHandler):crawl_config {}# minutes24 * 60:每隔一天重新爬取every(minutes24 * 60)def on_start(self):self.crawl(http://scrapy.org/, callbackself.index_page)…...
WPF DataGrid常用属性
AlternationCount属性:表示有几行不同的颜色来回替换,如果设置2则表示有两个颜色交替循环 AutoGenerateColumns属性:是否生成列 CanUserAddRows属性:用户是否可以添加行 CanUserDeleteRows属性:用户是否可以删除行 …...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...













