【C++初阶】四、类和对象(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)
=========================================================================
相关代码gitee自取:
C语言学习日记: 加油努力 (gitee.com)
=========================================================================
接上期:
【C++初阶】三、类和对象
(面向过程、class类、类的访问限定符和封装、类的实例化、类对象模型、this指针)
-CSDN博客
=========================================================================
引入:类的六个默认成员函数
如果一个类中什么成员都没有,简称为空类。
但空类中并不是什么都没有,任何类在什么都不写时,
编译器会自动生成以下六个默认成员函数,
默认成员函数:用户没有显式实现时,编译器会自动生成的成员函数称为默认成员函数
- 初始化和清理:
构造函数(1) -- 完成成员变量的初始化工作
析构函数(2) -- 完成一个对象结束生命周期后的资源清理工作
- 拷贝复制:
拷贝构造函数(3) -- 使用同类对象初始化创建对象
赋值重载(4) -- 把一个对象赋值给另一个对象
- 取地址重载:
主要是普通对象(5)和const对象取地址(6),这两个很少会自己实现
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一 . 构造函数(难)
构造函数的概念和特性:
C++构造函数的概念:
还是假设有以下Date类:
//日期类: class Date { public://我们自己定义的初始化函数:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}//打印日期函数:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private://私有成员函数:int _year; //年int _month; //月int _day; //日 };int main() {Date d1;d1.Init(2023, 11, 16);d1.Print();Date d1;d1.Init(2023, 11, 17);d1.Print();return 0; }
- 对于以上的Date类,可以通过我们自己定义的 Init共有函数(方法)给对象设置日期,
但如果每次创建对象时都需要调用该方法初始化对象成员的话,
会有点麻烦而且可能会忘记初始化,那能否在对象创建时就自动进行初始化呢?
- C++为了优化C语言需要自己初始化的情况,有了一个新概念:构造函数。
构造函数是特殊的成员函数,其名字和类名相同,
创建类类型对象时由编译器自动调用进行对象的初始化,
以保证每个数据成员都有一合适的初始值,并且在对象整个声明周期内只会调用一次
- 构造函数分为有参构造函数和无参构造函数,
我们在创建对象时可以设置各成员变量初始化的值,
如果没有设置,则对象初始化时会调用无参构造函数,
如果设置了,则对象初始化时会调用相应的有参构造函数Date类 -- 图示:
主函数通过构造函数创建对象 -- 图示:
---------------------------------------------------------------------------------------------
C++构造函数特征:
- 构造函数名和类名相同,构造函数没有返回值,
对象实例化时编译器会自动调用对应的构造函数
- 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,
一旦用户显式定义构造函数,编译器将不再自动生成构造函数,
所以如果定义了有参构造函数,最好再定义一个无参构造函数,
防止创建对象时需要无参构造函数而又无法调用到
- 构造函数也是函数,可以有参数,所以也可以对其设置缺省参数,
将一个有参构造函数(初始化全部成员变量的构造函数)的
所有参数都设置一个缺省参数(全缺省构造函数),
这样该构造函数就既实现了有参构造函数的任务,
又实现了无参构造函数的任务,因为初始化对象时如果不给初始化值,
那么有参构造函数的缺省参数就会发挥作用,实现无参构造函数的任务
这样一个构造函数就可以替代有参和无参两个构造函数了
- 构造函数支持重载,虽然支持重载,
但如果已经定义了全缺省构造函数,已经能够实现无参构造函数的情况下,
这时如果再定义一个无参构造函数,虽然构成了构造函数重载,
但是实际调用时是会出错的,因为全缺省构造函数和无参构造函数的功能重复了,
编译器就会不知道该调用哪个构造函数了
- 无参的构造函数和全缺省的构造函数都称为默认构造函数,
并且默认构造函数只能有一个(否则会有调用歧义)
注意:
无参构造函数、全缺省构造函数、编译器默认生成的构造函数,
都可以认为是默认构造函数
(不传参数还可以被调用的构造函数,都可以叫默认构造函数)全缺省构造函数 -- 图示:
编译器默认生成的构造函数的作用:
- C++中把类型分成了内置类型(基本类型)和自定义类型,
内置类型就是语言原生的数据类型(int、double、指针……);
自定义类型就是我们使用 class / struct / union 自己定义的类型。
关于编译器生成的默认构造函数,该构造函数会对我们未定义的成员变量进行初始化
- 不同编译器的初始化方式不同,
VS2013中:
如果对象的成员变量为内置类型,
默认生成构造函数不会对其进行处理(为随机值);
如果对象的成员变量为自定义类型,
默认生成构造函数则会调用该自定义类型的默认构造函数
VS2019中情况会更复杂:
如果对象的成员变量全是内置类型,
默认生成构造函数不会对其进行处理(为随机值);
如果对象的成员变量既有内置类型又有自定义类型,
则会对其中的内置类型进行处理(int类型成员变量会被初始化为0),
对其中的自定义类型,会调用该自定义类型的默认构造函数
- 所以默认生成的构造函数会根据对象的成员变量的情况来判断是否要对其进行处理,
如果对象的成员变量为自定义类型,就调用该自定义类型的默认构造函数;
如果是内置类型,则不进行处理(为随机值)
(会处理自定义类型,不一定处理内置类型(看编译器),建议统一当成不会进行处理)图示:
- 因此C++11中针对内置类型成员不初始化的缺陷,又打了一个补丁:
内置类型成员变量在类中声明时可以给默认值
(给了默认值又有定义显式构造函数的话,以显式构造函数为准)图示:
总结:
- 一般情况下,我们都要自己写构造函数
- 成员变量如果都是自定义类型,或者成员变量声明时给了缺省值,
那就可以考虑让编译器自己生成构造函数
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
二 . 析构函数
析构函数的概念和特性:
C++析构函数的概念:
- 通过前面对构造函数的了解,我们知道了一个对象是怎么来的,
可一个对象又是怎么没的呢?如果说构造函数是我们以前写的Init初始化函数,那么析构函数就是我们以前写的Destroy“销毁”函数
- 析构函数和构造函数的功能相反,但析构函数不是完成对对象本身的销毁,
局部对象销毁工作是由编译器完成的。
而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作
---------------------------------------------------------------------------------------------
C++析构函数的特性:
- 析构函数名 = 在类名前加上字符 “~” (按位取反符号)
- 析构函数没有返回值和函数参数
- 一个类只能有一个析构函数,若没有显式定义,编译器会自动生成默认的析构函数
(注:析构函数不支持重载)
- 对象声明周期结束时,C++编译系统会自动调用析构函数
析构函数 -- 图示:
编译器默认生成的构造函数的作用:
- 默认生成的析构函数,其行为跟构造函数的类似,
针对内置类型的成员变量,析构函数不会对其进行处理;
针对自定义类型的成员变量,析构函数也会调用该自定义类型的默认析构函数
- 如果类中没有申请资源,析构函数可以不写,直接使用编译器生成的默认析构函数,
比如之前写的Date日期类就可以不写;
而如果类中有申请资源,则一定要写析构函数,否则会导致资源(内存)泄漏,
比如Stack栈类就需要显式定义析构函数进行资源清理图示:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
三 . 拷贝构造函数(难)
拷贝构造函数的概念和特性:
C++拷贝构造函数的概念:
拷贝构造函数:
只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),
在使用已存在的类类型对象拷贝创建新对象时由编译器自动调用图示:
---------------------------------------------------------------------------------------------
C++拷贝构造函数的特性:
- 拷贝构造函数也是特殊的成员函数,是构造函数的一个重载形式
- 拷贝构造函数的参数只有一个且必须是类类型对象的引用,
使用传值方式作为其参数编译器会直接崩溃,因为会引发无穷递归调用
- 如果没有显式定义拷贝构造函数,编译器会生成默认的拷贝构造函数。
默认的拷贝构造函数拷贝对象时会按内存存储按字节序完成拷贝,
这种拷贝叫做浅拷贝,或者值拷贝注:
在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的(值拷贝),
而自定义类型则会调用该自定义类型的拷贝构造函数完成拷贝图示:
- 编译器生成的默认拷贝构造函数已经可以完成字节序的值的拷贝(值拷贝)了,
当类中没有涉及资源申请(申请动态空间等)时,
浅拷贝已经足够使用了,是否显式定义拷贝构造函数都可以;
但是一旦涉及到了资源申请时,则拷贝构造函数是一定要显式定义的,进行深拷贝图示:
- 拷贝构造函数典型调用场景:
使用已存在的对象来“拷贝”创建新对象、函数参数类型为类类型对象、
函数返回值类型为类类型对象注:
为了提高效率,一般对象传参时,尽量使用引用类型返回,
返回时根据实际场景,能用引用返回尽量使用引用返回
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
四 . 赋值运算符重载
运算符重载的使用和注意事项
引言:
对于内置类型(int、double……)的数据,我们可以直接对其使用运算符,
假设我们有整型变量a和b,我们可以对其使用:
a == b(判断相等) 、a > b(判断大小),
但对自定义类型的数据而言,就不能直接对其使用运算符,
因为编译器不知道怎么判断我们自定义的类型,所以需要我们自己定义其判断的规则图示 -- 自定义类型判断规则:
---------------------------------------------------------------------------------------------
运算符重载的使用:
- C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,
也具有其返回值类型、函数名字以及参数列表,
其返回值类型与参数列表和普通的函数类似
- 函数名字:关键字operator后接需要重载的运算符符号
(如:加法运算符重载 -- operator+)
- 函数原型:返回值类型 operator操作符(参数列表)
图示 -- 类外运算符重载:
---------------------------------------------------------------------------------------------
运算符重载的注意事项:
- 不能通过连接其它符号来创建新的操作符:比如operator@
- 重载操作符必须有一个类类型参数
- 用于内置类型的运算符,其含义不能改变,
例如:内置的整型+ ,不能改变其含义( + 和 += 是不一样的 )
- 重点:
作为类成员函数重载时,其形参看起来比操作数数目少一个,
因为成员函数的第一个参数为隐藏的this指针
- 注意以下五个运算符不能重载:
“ .* ” 、“ :: ” 、“ sizeof ” 、“ ?: ” 、“ . ”图示 -- 类中运算符重载:
- 一个类要重载哪些运算符,主要看这个运算符对这个类来说有没有意义,
有意义就可以重载,没有意义就不要重载,
对日期类来说,日期的 +(加) *(乘) /(除) 都没有意义,但 -(减) 是有意义的,
两个日期相减可以计算两日期相差了多少天;
日期+日期没有意义,但日期+整型是有意义的,
如:d1 + 100 ,计算d1日期的100天后的日期图示 -- 类中实现 += 和 + 运算符重载:
(注:“+=”运算符重载中要设置返回值 -- return *this ,这里忘了写了)
赋值运算符(=)重载
赋值运算符 -- "=" ,赋值运算符重载就是让自定义类型也能像内置类型一样使用”=“
赋值运算符重载格式:
- 参数类型:const T&
const修饰参数,能够防止赋值(拷贝)时左右值写反了,导致改变了原对象
T& 传参引用接收右值的“别名”,提高传参效率
- 返回值类型:T&
引用返回可以提高返回的效率,设置返回值还为了支持“=”的连续赋值
- 定义赋值运算符重载函数时,需要检测是不是“自己给自己赋值”的情况
- 最终返回*this(即返回被赋值对象本身),能够符合“=”连续赋值的含义
- 用户没有显式实现时,编译器会生成一个默认的赋值运算符重载函数,
其行为和拷贝构造函数类似:
针对内置类型成员变量:进行 值拷贝(浅拷贝)
针对自定义类型成员变量:会调用该自定义类型的 赋值运算符重载函数
注意:
如果类中没有“资源”(Date类),赋值运算符重载函数要不要显式定义都可以;
如果类中有“资源”(Stack类),赋值运算符重载函数必须要显式定义
赋值运算符只能重载成类的成员函数(只能在类中定义重载),不能重载为全局函数
原因:
赋值运算符重载函数如果不显式实现,编译器会生成一个默认的。
此时如果再在类外实现一个全局的赋值运算符重载函数,
就会和编译器在类中生成的默认赋值运算符重载函数冲突了,
所以赋值运算符重载函数只能是类的成员函数图示 -- 以Date类为例:
相关文章:
【C++初阶】四、类和对象(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)
相关代码gitee自取: C语言学习日记: 加油努力 (gitee.com) 接上期: 【C初阶】三、类和对象 (面向过程、class类、类的访问限定符和封装、类的实例化、类对象模型、this指针) -CSDN博客 引入:类的六个默认成员函数…...
js粒子效果(二)
效果: 代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Particle Animation</title><…...
01.让自己习惯C++
让自己习惯C 条款1:视C为一个语言联邦 条款1中提到了将C看作为一个“语言联邦”的概念。具体来说,“语言联邦”是指将C看作由多种不同的子语言组成的联邦。每种子语言都有自己的惯用法、工具和库,可以用来解决特定的问题。因此,…...
ElementUI table+dialog实现一个简单的可编辑的表格
table组件如何实现可编辑呢? 我的需求是把table组件那样的表格,实现它点击可以弹出一个框,然后在这个框里面输入你的东西,然后将他回显回去,当然,输入的有可能是时间啥的。 为什么要弹出弹层不在框上直接…...
Rust语言精讲:数据类型全解析
大家好!我是lincyang。 今天,我们将深入探讨Rust语言中的数据类型,这是理解和掌握Rust的基础。 Rust语言数据类型概览 Rust是静态类型语言,所有变量类型在编译时确定。Rust的数据类型分为两类:标量类型和复合类型。…...
《数据结构、算法与应用C++语言描述》-代码实现散列表(线性探查与链式散列)
散列表 完整可编译运行代码:Github:Data-Structures-Algorithms-and-Applications/_22hash/ 定义 字典的另一种表示方法是散列(hashing)。它用一个散列函数(也称哈希函数)把字典的数对映射到一个散列表(…...
Hadoop学习笔记:运行wordcount对文件字符串进行统计案例
文/朱季谦 我最近使用四台Centos虚拟机搭建了一套分布式hadoop环境,简单模拟了线上上的hadoop真实分布式集群,主要用于业余学习大数据相关体系。 其中,一台服务器作为NameNode,一台作为Secondary NameNode,剩下两台当…...
python编写简单登录系统(密码混淆加密)
输入非123的数字会显示输入123选项,输入空格或者回车会报错,因为choice设置成int型先输入2个正常账户进去预防了用户名为空,密码为空或者小于3个,用户名已存在3种情况只有用户名和对应的密码都输入正确才能登录成功输入选项3退出代…...
UVA1025 城市里的间谍 A Spy in the Metro
UVA1025 城市里的间谍 A Spy in the Metro 题面翻译 题目大意 某城市地铁是一条直线,有 n n n( 2 ≤ n ≤ 50 2\leq n\leq 50 2≤n≤50)个车站,从左到右编号 1 … n 1\ldots n 1…n。有 M 1 M_1 M1 辆列车从第 1 1 1 站开…...
【科普知识】什么是步进电机?
德国百格拉公司于1973年发明了五相混合式步进电机及其驱动器,1993年又推出了性能更加优越的三相混合式步进电机。我国在80年代以前,一直是反应式步进电机占统治地位,混合式步进电机是80年代后期才开始发展。 步进电机是一种用电脉冲信号进行…...
AWS云服务器EC2实例实现ByConity快速部署
1. 前言 亚马逊是全球最大的在线零售商和云计算服务提供商。AWS云服务器在全球范围内都备受推崇,被众多业内人士誉为“云计算服务的行业标准”。在国内,亚马逊AWS也以其卓越的性能和服务满足了众多用户的需求,拥有着较高的市场份额和竞争力。…...
Docker的项目资源参考
Docker的项目资源包括以下内容: Docker官方网站:https://www.docker.com/ Docker Hub:https://hub.docker.com/ Docker文档:https://docs.docker.com/ Docker GitHub仓库:https://github.com/docker Docker官方博客…...
wsl-ubuntu 系统端口总被主机端口占用问题解决
wsl-ubuntu 系统端口总被主机端口占用问题解决 0. 问题描述1. 解决方法 0. 问题描述 wsl-ubuntu 子系统中的服务,总是启动失败,错误信息是端口被占用。 用一些命令查看,被占用的端口也没有用服务启动。 1. 解决方法 运行, ne…...
详解自动化之单元测试工具Junit
目录 1.注解 1.1 Test 1.2 BeforeEach 1.3 BeforeAll 1.4 AfterEach 1.5 AfterAll 2. 用例的执行顺序 通过 order() 注解来排序 3. 参数化 3.1 单参数 3.2 多参数 3.3 多参数(从第三方csv文件读取数据源) 3.4 动态参数ParameterizedTest MethodSource() 4. 测试…...
超声波雪深传感器冬季里的科技魔法
在冬季的某个清晨,当你打开大门,被厚厚的积雪覆盖的大地映入眼帘,你是否曾想过,这片雪地的深度是多少?它又如何影响着我们的生活和环境?今天,我们将为你揭开这个谜团,介绍一款神秘的…...
2023年【熔化焊接与热切割】免费试题及熔化焊接与热切割模拟考试
题库来源:安全生产模拟考试一点通公众号小程序 熔化焊接与热切割免费试题是安全生产模拟考试一点通生成的,熔化焊接与热切割证模拟考试题库是根据熔化焊接与热切割最新版教材汇编出熔化焊接与热切割仿真模拟考试。2023年【熔化焊接与热切割】免费试题及…...
【数据结构】—搜索二叉树(C++实现,超详细!)
🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:消えてしまいそうです—真夜中 1:15━━━━━━️💟──────── 4:18 🔄 ◀️ ⏸ ▶️…...
机器人算法—ROS TF坐标变换
1.TF基本概念 (1)什么是TF? TF是Transformations Frames的缩写。在ROS中,是一个工具包,提供了坐标转换等方面的功能。 tf工具包,底层实现采用的是一种树状数据结构,根据时间缓冲并维护多个参考…...
路由VRRP配置例子
拓朴如下: 主要配置如下: [R1] interface GigabitEthernet0/0/0ip address 10.1.1.1 255.255.255.0 vrrp vrid 1 virtual-ip 10.1.1.254vrrp vrid 1 priority 200vrrp vrid 1 preempt-mode timer delay 20 # interface GigabitEthernet0/0/1ip address …...
OpenGL 绘制点与三角形(Qt)
文章目录 一、简介二、实现代码三、实现效果一、简介 这里对OpenGL中点与三角形相关绘制操作进行封装,方便后续点云数据与模型数据的渲染。 二、实现代码 这里我们先创建一个基类Drawable,后续的点、线、面等,均会继承该类: Drawable.h #ifndef DRAWABLE_H #define DRAWABL…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...














