【C++】——类和对象(中)——默认成员函数

一、类的默认成员函数

默认成员函数就是用户没有显示实现,不过编译器会自动生成的成员函数,称为默认成员函数。一个类默认成员函数一共有6个,在我们不写的情况下,编译器就会自动生成这6个成员函数,不过我们重点要学习的是前面四个,后面两个了解即可。还有就是在C++11后还增加了两个默认成员函数,移动构造和移动赋值,这个我们后续讲解C++11的时候也会进行讲解。

默认成员函数比较复杂,我们主要从下面两个方面进行学习理解:

1、我们不写的时候,编译器默认生成的函数行为是什么?是否可以满足我们的需求?

2、编译器默认生成的函数不满足我们的需求的时候,那么我们就要自己去实现,那么要如何进行       实现呢?

下面我们就从几种默认成员函数来入手:

二、构造函数

构造函数是一种特殊的成员函数,它的功能类似我们在前面实现链表、栈、队列等的数据结构的初始化函数一样,其是用来实现实例化对象初始化始化对象。还要注意的是,虽然名字叫做构造函数,但是其不会去开空间,其是局部变量进行初始化的。

下面是构造函数要注意的点:
1、构造函数的函数名和类的名字一样

2、构造函数无返回值,而且我们在定义和声明的时候连void都不需要写

3、对象实例化的时候系统就会自动调用构造函数

4、构造函数可以重载

下面我们通过代码来深入学习一下:

可以看到我们上面没有去调用这个构造函数,那么我们看看其运行结果是否会自动调用这个构造函数使得我们的成员变量初始化:

   可以看到我们的成员变量被初始化成功了。所以说我们在实例化对象的时候编译器会自动调用我     们的构造函数。

   我们上面还提到了,我们的构造函数还可以重载,也就是说我们的构造函数可以不止一个,可以      有多个,然后编译器会根据我们传的参数来进行判断该调用那个:

     运行结果如下:
     我们可以看到当我们要调用的是需要进行传参的构造函数,那么我们在实例化的时候,就需要        在后面加上括号然后进行传参。

     那么我们对于没有参数的那个构造函数,我们在实例化对象的时候加个括号是否可以呢?

      答案是不行滴:

    可以看到编译器直接就报错了。

     构造函数的使用要求还有以下几个:
5、如果类中没有显示定义构造函数,那么C++编译器会自动生成一个无参的默认构造函数,一旦       显示定义那么编译器不再生成。

6、无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成构造函数这三种构造函数都       叫默认构造函数。但是我们前面学习函数重载的时候就知道,这三个函数就只能存在一个,不       可以共存。无参构造函数和全缺省构造函数虽然构造函数重载,但是不传参调用时会有歧义。

      可以看到错误信息中提示到,函数的调用不明确。

7、我们不写构造函数,那么编译器就会自动生成构造函数,对于内置类型成员变量的初始化是不        确定的,那么具体被初始化成什么就由编译器来确定了。对于自定义类型变量要求调用这个成        员变量的默认构造函数进行初始化。如果这个成员变量没有默认构造函数,那么编译器就会报        错吗,那么我们要初始化这个变量就需要用到初始化列表,初始化列表我们后续再进行讲解。

     在C++中将数据类型分为内置类型和自定义类型

     内置类型:int、char、double等等

     自定义类型:我们使用class和struct等关键字进行定义的类型

下面我们就来看看编译器自动生成的构造函数是如何的:

 我们可以看到我们在定义类的时候我们没有写构造函数的,那么我们在实例化对象的时候,我们的编译器就会自动帮我们默认构造函数,但是其具体是初始化什么内容我们就不知道了,我们上面的代码对成员变量的初始化就没啥有要求了。

还有一种情况就是我们的成员变量也是一个类,然后我们的成员变量有构造函数,那么我们这个类就可以不写构造函数了,那么其就会使用成员变量那个类的构造函数。

比如我们前面学习的数据结构中,使用栈实现队列,那么我们的队列类中的成员变量就是两个栈:

可以看到两个栈确定被初始化为了4。

要是我们的栈中的构造函数,其参数修改成需要进行传参的函数,那么就需要用来初始化列表了,

 不过我们可以知道的是,对于大部分的类,我们都需要自己去写构造函数,因为编译器默认的很多情况都不能满足需求。

三、析构函数

析构函数的功能和构造函数是相反的,有点类似于我们在实现栈的时候的Destroy函数的功能,用来完成对对象中的清理释放工作。要注意的是其不是完成对对象的销毁,比如局部对象是有栈帧的,函数结束的时候会销毁栈帧,那么这个局部对象也就跟着销毁了,所以对于局部对象我们是不要理的,其也不需要析构函数。但是C++中规定了对象在销毁时会自动调用析构函数,用于完成资源的清理。如果对于一个类没有资源要进行释放的,那么理论上就不需要析构函数。

下面是析构函数使用上的一些要求:

1、析构函数名是在类名前加上字符~。

2、析构函数和构造函数一样是无参无返回值的,而且也不需要写void。

3、一个类中只能有一个析构函数只能有一个析构函数。若未显示定义,那么系统就会自动生成默       认的析构函数。

4、对象生命周期结束时,系统就会自动调用析构函数。

5、一个局部域有多个实例化对象的时候,后定义的会先进行析构。

下面我们通过代码来感受一下:

 

可以看到st1和st2都已经按照我们给的参数进行初始化了,然后我们继续往下运行:

 可以看到我们是先将st2的销毁了,然后再对st1进行销毁的。

6、和构造函数一样,我们不写的话,那么编译器就会自动去生成这个函数,其不对内置类型的成       员变量操作,自定义类的成员变量就会进行处理。

7、还需要注意的是,我们显示写析构的时候,对于自定义类型的成员其也会调用它的析构函数,       不会受到在这个类中写的析构函数的影响。也就是说自定义类型不论什么情况下都会去自动调       用析构函数。

我们前面学习数据结构的时候,我们写了道使用栈实现队列的题目,下面我们通过这个例子来看看,我们可以在析构函数中打印一些东西来看这个函数被调用了多少次:

首先就是,我们知道的是,我们的队列自定义类型中,其有两个成员变量,编译器会其调用这个成员变量的析构函数,那么就会其栈类中调用,那么我们一共两个栈,所以其调用两次。

 还有就是我们要是没有去向操作系统申请空间,那么我们的析构函数其实是可以不写的,直接使用编译器默认生成的析构函数即可,所以当我们需要进行空间申请的时候,一定要写析构函数,不然就会造成内存泄漏。

四、拷贝构造函数

如果一个构造函数的第一个参数是自身类类型的引用,而且任何地方的参数都有默认值,那么此函数就叫做拷贝构造函数。

下面是拷贝构造函数使用的时候的特点:

1、拷贝构造函数是构造函数的一个重载。

2、拷贝构造函数的第一个参数必须是类类型对象的引用,使用传值方式的话编译器会直接报错,       这是因为在语法逻辑上会导致无穷递归调用。拷贝构造函数也可以有多个参数,但是第一个参       数一定要保证是类类型对象的引用,而且后面的参数一定要有缺省值。

我们上面的代码,将a1作为参数传给a2的拷贝构造函数,那么a2的值就会和a1的一样了。

还有就是我们的拷贝构造函数的参数部分可以加一个const关键字,因为我们不想被拷贝的对象被改变,还有就是对于被const关键字修饰的对象我们也可将其拷贝。

 那么为啥不可以传值呢?这是因为传值的话,其会导致无穷递归调用拷贝构造函数,那是为啥会导致这个问题呢?

这是因为我们传值的时候,是一种浅拷贝,那么会创建一个临时变量先将参数的进行拷贝,但是我们在创建这个临时变量的时候,因为其也是类类型,那么其进行拷贝那么就会去调用拷贝构造函数,那么就造成了无穷递归。

引用传参的话,那么其是使用的实参的别名,那么在传参的过程中是不会产生拷贝的,其实际上就直接对这个传入的参数的内容进行拷贝了,所以不存在浅拷贝,就直接进入到函数中了,所以不会导致无穷递归。

3、C++中规定了自定义类型对象进行拷贝的行为必须调用拷贝构造,所以自定义类型传参和传值       都会调用拷贝构造函数来完成。

4、要是未显示定义拷贝构造函数,那么编译器就会自动生成拷贝构造函数,那么自动生成的拷贝        构造函数对内置类型的成员变量会完成值拷贝,即一个字节一个字节的拷贝,和我们前面学习        C语言的时候对字符串进行拷贝一样,对于自定义类型的成员变量那么就会调用其拷贝构造函        数。

不过对于一些比较复杂的成员变量,要是使用编译器自动生成的拷贝构造函数,会造成不好的效果,比如我们的栈成员变量:

 

 

可以看到我们的程序就直接运行不起来了,这是因为st1初始化的时候,_a会被分配一块空间,但是st2就是st1的浅拷贝,但是此时st2中的_arr和st1中的_arr使用的是一块空间了。

所以这种情况下我们一定要自己去写拷贝构造函数来实现深拷贝。

5、像我们上面的Date类中,其成员变量全是内置类型而且没有什么指向资源,那么编译器自动生        成的拷贝构造函数就可以完成了,所以我们可以不去写,但是像Stack类这样的,虽然其也是          内置类型,但是_arr其指向了资源,编译器自动生成的拷贝构造函数完成的是值拷贝,达不到        我们的需求,所以我们要自己实现一个深拷贝。还有就是很前面的使用栈实现队列中的队列类        也是一样,其成员变量的栈的类其有显示的拷贝构造函数,那么我们的队列类中可以不写,其        会去调用栈的拷贝构造函数。

      下面有个技巧:

       如果一个类显示的实现了析构函数,而且释放了资源,那么其就需要显示的写拷贝构造。

6、传值返回会产生一个临时对象的拷贝构造,传值引用返回,返回的是返回对象的别名,那么就没产生拷贝。那么如果返回对象是一个当前函数的局部域的局部对象,那么函数结束就销毁了,那么使用引用返回是有问题的,此时的引用就是野引用了。

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

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

相关文章

MATLAB知识点总结

1.将A图与B图相同范围内归一化显示在同一个figure上: figure, plot(A(150:450,500)/max(A(150:450,500))) hold on plot(D(150:450,500)/max(D(150:450,500)),‘R’) 将两幅图像的一定范围显示在同一图像上。 figure,plot(A(350,100:450)) hold on plot(G(350,100:4…

易天光通信10G SFP+ 1550nm 120KM 双纤光模块:远距离传输的实力担当

目录 前言 一、10G SFP双纤光模块概述 二、易天10G SFP 120KM 双纤光模块核心优势与应用 核心优势: 主要关键应用如下: 三、易天10G SFP 120KM 双纤光模块客户优势 总结 关于易天 前言 在构建高效稳定的网络架构时,10G SFP 光模块 12…

【深度学习】神经网络 批量标准化-part6

九、批量标准化是一种广泛使用的神经网络正则化技术,对每一层的输入进行标准化,进行缩放和平移,目的是加速训练,提高模型稳定性和泛化能力,通常在全连接层或是卷积层之和,激活函数之前使用核心思想对每一批…

【数据可视化-67】基于pyecharts的航空安全深度剖析:坠毁航班数据集可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

【科研绘图系列】R语言绘制分组箱线图

文章目录 介绍 加载R包 数据下载 导入数据 画图1 画图2 合并图 系统信息 参考 介绍 【科研绘图系列】R语言绘制分组箱线图 加载R包 library(ggplot2) library(patchwork)rm(list = ls()) options(stringsAsFactors = F)

基于Android的旅游计划App

项目介绍系统打开进入登录页面,如果没有注册过账号,点击注册按钮输入账号、密码、邮箱即可注册,注册后可登录进入系统,系统分为首页、预订、我的三大模块,下面具体详细说说三大模块功能说明。1.首页显示旅游备忘或旅游…

【LeetCode 2163. 删除元素后和的最小差值】解析

目录LeetCode中国站原文原始题目题目描述示例 1:示例 2:提示:讲解分割线的艺术:前后缀分解与优先队列的完美邂逅第一部分:算法思想 —— “分割线”与前后缀分解1. 想象一条看不见的“分割线”2. 前后缀分解&#xff1…

控制鼠标和键盘

控制鼠标和键盘的Python库Python中有多个库可以用于控制鼠标和键盘,常用的包括pyautogui、pynput、keyboard和mouse等。这些库提供了模拟用户输入的功能,适用于自动化测试、GUI操作等场景。使用pyautogui控制鼠标pyautogui是一个跨平台的库,支…

基于按键开源MultiButton框架深入理解代码框架(二)(指针的深入理解与应用)

文章目录2、针对该开源框架理解3、分析代码3.1 再谈指针、数组、数组指针3.2 继续分析源码2、针对该开源框架理解 在编写按键模块的框架中,一定要先梳理按键相关的结构体、枚举等变量。这些数据是判断按键按下、状态跳转、以及绑定按键事件的核心。 这一部分定义是…

web前端渡一大师课 CSS属性计算过程

你是否了解CSS 的属性计算过程呢? <body> <h1>这是一个h1标题</h1> </body> 目前我们没有设置改h1的任何样式,但是却能看到改h1有一定的默认样式,例如有默认的字体大小,默认的颜色 那么问题来了,我们这个h1元素上面除了有默认字体大小,默认颜色等…

Redis高频面试题:利用I/O多路复用实现高并发

Redis 通过 I/O 多路复用&#xff08;I/O Multiplexing&#xff09;技术实现高并发&#xff0c;这是其单线程模型能够高效处理大量客户端连接的关键。以下是通俗易懂的解释&#xff0c;结合 Redis 的工作原理&#xff0c;详细说明其实现过程。 1. 什么是 I/O 多路复用&#xff…

爬虫小知识(二)网页进行交互

一、提交信息到网页 1、模块核心逻辑 “提交信息到网页” 是网络交互关键环节&#xff0c;借助 requests 库的 post() 函数&#xff0c;能模拟浏览器向网页发数据&#xff08;如表单、文件 &#xff09;&#xff0c;实现信息上传&#xff0c;让我们能与网页背后的服务器 “沟通…

WPF学习(五)

文章目录一、FileStream和StreamWriter理解1.1、具体关系解析1.2、类比理解1.3、总结1.4、示例代码1.5、 WriteLine()和 Write&#xff08;&#xff09;的区别1.6、 StreamWriter.Close的作用二、一、FileStream和StreamWriter理解 在 C# 中&#xff0c;StreamWriter 和 FileS…

ctf.show-web习题-web2-最简单的sql注入-flag获取详解、总结

解题思路打开靶场既然提示是最简单的sql注入了&#xff0c;那么直接尝试永真登录1 or 11#这里闭合就是简单的单引号可以看到没登录成功&#xff0c;但是有回显&#xff1a;欢迎你&#xff0c;ctfshowsql注入最喜欢的就是回显了&#xff01;这题的思路就是靠这个回显&#xff0c…

upload-labs 靶场通关(1-20)

目录 Pass-01(JS 绕过) Pass-02(文件类型验证) Pass-03(黑名单验证) Pass-04(黑名单验证.htaccess) Pass-05(大小写绕过) Pass-06(末尾空格) Pass-07(增加一个.) Pass-08(增加一个::$DATA) Pass-09&#xff08;代码不严谨&#xff09; Pass-10&#xff08;PPHPHP&am…

[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+vue实现的酒店预订管理系统,推荐!

摘 要 使用旧方法对酒店预订信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在酒店预订信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次开发的酒店预订管理系…

LSTM入门案例(时间序列预测)| pytorch实现(可复现)

需求 假如我有一个时间序列&#xff0c;例如是前113天的价格数据&#xff08;训练集&#xff09;&#xff0c;然后我希望借此预测后30天的数据&#xff08;测试集&#xff09;&#xff0c;实际上这143天的价格数据都已经有了。这里为了简单&#xff0c;每一天的数据只有一个价…

Axure RP 10 预览显示“无标题文档”的空白问题探索【护航版】

1. 安装情况 官网 Axure RP 10&#xff1a;Download Axure RP 10 - Axure &#xff08;PS&#xff1a;11都出了&#xff09; 版本&#xff1a;10.0.0.3924 激活码&#xff1a;49bb9513c40444b9bcc3ce49a7a022f9 &#xff08;10/11都可以用&#xff0c;但只尝试了10&#xff…

基于SpringBoot+Vue的汽车租赁系统(协同过滤算法、腾讯地图API、支付宝沙盒支付、WebsSocket实时聊天、ECharts图形化分析)

系统亮点&#xff1a;协同过滤算法、腾讯地图API、支付宝沙盒支付、WebsSocket实时聊天、ECharts图形化分析&#xff1b;01系统开发工具与环境搭建—前后端分离架构项目架构&#xff1a;B/S架构运行环境&#xff1a;win10/win11、jdk17前端&#xff1a;技术&#xff1a;框架Vue…

数据结构入门:像整理收纳一样简单!

在我们生活中&#xff0c;经常会面对这样的问题&#xff1a; “我要怎么整理我的衣柜&#xff1f;” “电脑里照片太多了&#xff0c;怎么归类才方便查找&#xff1f;” 其实&#xff0c;程序员也有类似的烦恼。他们不整理衣柜&#xff0c;而是“整理数据”。而这门关于如何“收…