【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++中把类型分成了内置类型基本类型自定义类型
    内置类型就是语言原生的数据类型intdouble指针……);
    自定义类型就是我们使用 class / struct / union 自己定义的类型
    关于编译器生成的默认构造函数该构造函数会对我们未定义的成员变量进行初始化
                   
  • 不同编译器初始化方式不同
    VS2013中:
    如果对象的成员变量为内置类型
    默认生成构造函数不会对其进行处理为随机值);
    如果对象的成员变量为自定义类型
    默认生成构造函数则会调用该自定义类型的默认构造函数
    VS2019情况会更复杂

    如果对象的成员变量全是内置类型
    默认生成构造函数不会对其进行处理为随机值);
    如果对象的成员变量既有内置类型又有自定义类型
    则会对其中的内置类型进行处理int类型成员变量会被初始化为0),
    对其中的自定义类型,会调用该自定义类型的默认构造函数
               
  • 所以默认生成的构造函数根据对象的成员变量的情况判断是否要对其进行处理
    如果对象的成员变量为自定义类型,就调用该自定义类型的默认构造函数
    如果是内置类型,则不进行处理为随机值
    会处理自定义类型不一定处理内置类型(看编译器),建议统一当成不会进行处理
图示:

           

  • 因此C++11中针对内置类型成员不初始化的缺陷,又打了一个补丁
    内置类型成员变量类中声明可以给默认值
    给了默认值又有定义显式构造函数的话显式构造函数为准
图示:

                     

总结:
  • 一般情况下我们都要自己写构造函数
                 
  • 成员变量如果都是自定义类型或者成员变量声明时给了缺省值
    那就可以考虑让编译器自己生成构造函数

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

二 . 析构函数

析构函数的概念和特性:

                 

C++析构函数的概念:

            

  • 通过前面对构造函数的了解,我们知道了一个对象是怎么来的
    可一个对象又是怎么没的呢?如果说构造函数是我们以前写的Init初始化函数

    那么析构函数就是我们以前写的Destroy销毁函数
                            

  • 析构函数构造函数功能相反析构函数不是完成对对象本身的销毁
    局部对象销毁工作是由编译器完成
    对象销毁时会自动调用析构函数完成对象中资源的清理工作

                          

                          
---------------------------------------------------------------------------------------------

                    

C++析构函数的特性:

                

  • 析构函数名 = 在类名前加上字符 ~” (按位取反符号
                        
  • 析构函数没有返回值函数参数
                
  • 一个类只能有一个析构函数没有显式定义编译器自动生成默认的析构函数
    析构函数不支持重载
                      
  • 对象声明周期结束C++编译系统自动调用析构函数

析构函数 -- 图示:

                            

编译器默认生成的构造函数的作用:
  • 默认生成的析构函数其行为跟构造函数的类似
    针对内置类型的成员变量析构函数不会对其进行处理
    针对自定义类型的成员变量析构函数也会调用该自定义类型的默认析构函数
                       
  • 如果类中没有申请资源析构函数可以不写直接使用编译器生成的默认析构函数
    比如之前写的Date日期类就可以不写
    而如果类中有申请资源则一定要写析构函数否则会导致资源内存泄漏
    比如Stack栈类需要显式定义析构函数进行资源清理
图示:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

三 . 拷贝构造函数(难)

拷贝构造函数的概念和特性:

                

C++拷贝构造函数的概念:

                     

  • 拷贝构造函数
    只有单个形参该形参对本类类型对象的引用一般常用const修饰),
    在使用已存在的类类型对象拷贝创建新对象时编译器自动调用

图示:

                          

                          
---------------------------------------------------------------------------------------------

                    

C++拷贝构造函数的特性:

                       

  • 拷贝构造函数也是特殊的成员函数构造函数的一个重载形式
                     
  • 拷贝构造函数的参数只有一个必须是类类型对象的引用
    使用传值方式作为其参数编译器会直接崩溃因为会引发无穷递归调用
                           
  • 如果没有显式定义拷贝构造函数编译器会生成默认的拷贝构造函数
    默认的拷贝构造函数拷贝对象时会按内存存储按字节序完成拷贝
    这种拷贝叫做浅拷贝或者值拷贝
注:

在编译器生成的默认拷贝构造函数内置类型按照字节方式直接拷贝值拷贝),
自定义类型则会调用该自定义类型的拷贝构造函数完成拷贝

图示:

                

                

  • 编译器生成的默认拷贝构造函数已经可以完成字节序的值的拷贝值拷贝
    当类中没有涉及资源申请申请动态空间等
    浅拷贝已经足够使用是否显式定义拷贝构造函数都可以
    但是一旦涉及到了资源申请拷贝构造函数一定要显式定义进行深拷贝
​​​​​​​图示:

                   

  • 拷贝构造函数典型调用场景
    使用已存在的对象拷贝创建新对象函数参数类型类类型对象
    函数返回值类型类类型对象
注:

为了提高效率一般对象传参尽量使用引用类型返回
返回时根据实际场景能用引用返回尽量使用引用返回

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

四 . 赋值运算符重载

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

                   

引言:

对于内置类型intdouble……)数据我们可以直接对其使用运算符
假设我们有整型变量ab,我们可以对其使用
​​​​​​​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类为例:

 ​​​​

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

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

相关文章

如何使用springboot服务端接口公网远程调试——实现HTTP服务监听

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 二. 内网穿透2.1 安装…

ATA-2042高压放大器在细胞的剪切应力传感器研究中的应用

微流控技术是一种通过微小的通道和微型装置对流体进行精确操控和分析的技术。它是现代医学技术发展过程中的一种重要的生物医学工程技术&#xff0c;具有广泛的应用前景和重要性。它在高通量分析、个性化医疗、细胞筛选等方面有着巨大的潜力&#xff0c;Aigtek安泰电子今天就将…

HR8833 双通道H桥电机驱动芯片

HR8833为玩具、打印机和其它电机一T化应用提供一种双通道电机驱动方案。HR8833提供两种封装&#xff0c;一种是带有L露焊盘的TSSOP-16封装&#xff0c;能改进散热性能&#xff0c;且是无铅产品&#xff0c;引脚框采用100&#xff05;无锡电镀。另一种封装为SOP16&#xff0c;不…

智驾芯片全矩阵「曝光」,这家企业的车载品牌正式官宣

随着汽车智能化加速&#xff0c;智能驾驶芯片格局逐渐清晰。 针对L0-L2&#xff0c;业内基本采用智能前视一体机方案&#xff1b;要实现高速NOA、城市NOA等更为高阶的智驾功能等&#xff0c;则基本采用域控制器方案。从前视一体机至域控&#xff0c;再逐步演进到舱驾一体、中央…

python基于DETR(DEtection TRansformer)开发构建钢铁产业产品智能自动化检测识别系统

在前文中我们基于经典的YOLOv5开发构建了钢铁产业产品智能自动化检测识别系统&#xff0c;这里本文的主要目的是想要实践应用DETR这一端到端的检测模型来开发构建钢铁产业产品智能自动化检测识别系统。 DETR (DEtection TRansformer) 是一种基于Transformer架构的端到端目标检…

【Django使用】10大章31模块md文档,第5篇:Django模板和数据库使用

当你考虑开发现代化、高效且可扩展的网站和Web应用时&#xff0c;Django是一个强大的选择。Django是一个流行的开源Python Web框架&#xff0c;它提供了一个坚实的基础&#xff0c;帮助开发者快速构建功能丰富且高度定制的Web应用 全套Django笔记直接地址&#xff1a; 请移步这…

外汇天眼:多名投资者账户被恶意清空,远离volofinance!

最近&#xff0c;外汇平台volofinance因有多名投资者投诉&#xff0c;“荣幸”成为外汇天眼黑平台榜单中的一员&#xff0c;那么volofinance到底做了什么导致投资者前来投诉曝光呢&#xff1f; 起底volofinace 在网络搜索中&#xff0c;关于volofinance的信息少之又少&#xf…

成为AI产品经理——模型评估指标

目录 一、模型评估分类 1.在线评估 2.离线评估 二、离线模型评估 1.特征评估 ① 特征自身稳定性 ② 特征来源稳定性 ③ 特征成本 2.模型评估 ① 统计性评估 覆盖度 最大值、最小值 分布形态 ② 模型性能指标 分类问题 回归问题 ③ 模型的稳定性 模型评估指标分…

配置mvn打包参数,不同环境使用不同的配置文件

方法一&#xff1a; 首先在/resource目录下创建各自环境的配置 要在不同的环境中使用不同的配置文件进行Maven打包&#xff0c;可以使用Maven的profiles特性和资源过滤功能。下面是配置Maven打包参数的步骤&#xff1a; 在项目的pom.xml文件中&#xff0c;添加profiles配置…

第一个Mybatis项目

&#xff08;一&#xff09;为什么要用Mybatis? &#xff08;1&#xff09;Mybatis对比JDBC而言&#xff0c;sql&#xff08;单独写在xml的配置文件中&#xff09;和java编码分开&#xff0c;功能边界清晰&#xff0c;一个专注业务&#xff0c;一个专注数据。 &#xff08;2&…

【C++】:多态

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

Linux(CentOS7)上安装mysql

在CentOS中默认安装有MariaDB&#xff08;MySQL的一个分支&#xff09;&#xff0c;可先移除/卸载MariaDB。 yum remove mariadb // 查看是否存在mariadb rpm -qa|grep -i mariadb // 卸载 mariadb rpm -e --nodeps rpm -qa|grep mariadb yum安装 下载rpm // 5.6版本 wge…

XML映射文件

<?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace"org.mybatis.example.BlogMapper&q…

conan 入门(三十二):package_info中配置禁用CMakeDeps生成使用项目自己生成的config.cmake

conanfile.py中定义的package_info()方法用于向package的调用者(conumer)提供包库名&#xff0c;编译/连接选项&#xff0c;文件夹等等信息&#xff0c;有了这些信息构建工具的generator就可以根据它们生成对应的文件&#xff0c;用于调用者引用package. 比如基于cmake的CMakeD…

安全地公网访问树莓派等设备的服务 内网穿透--frp 23年11月方法

如果想要树莓派可以被公网访问&#xff0c;可以选择直接网上搜内网穿透提供商&#xff0c;一个月大概10块钱&#xff0c;也有免费的&#xff0c;但是免费的速度就不要希望很好了。 也可以选择接下来介绍的frp&#xff0c;这种方式不需要付费&#xff0c;但是需要你有一台有着公…

vue3自定义拖拽指令

<template><div v-move class"box"></div> </template><script setup lang"ts"> import { Directive } from vue const vMove:Directive (el:HTMLElement) >{const mousedown (e:MouseEvent) >{// 鼠标按下const s…

【Golang】解决使用interface{}解析json数字会变成科学计数法的问题

在使用解析json结构体的时候&#xff0c;使用interface{}接数字会发现变成了科学计数法格式的数字&#xff0c;不符合实际场景的使用要求。 举例代码如下&#xff1a; type JsonUnmStruct struct {Id interface{} json:"id"Name string json:"name"…

Linux 的性能调优的思路

Linux操作系统是一个开源产品&#xff0c;也是一个开源软件的实践和应用平台&#xff0c;在这个平台下有无数的开源软件支撑&#xff0c;我们常见的apache、tomcat、mysql等。 开源软件的最大理念是自由、开放&#xff0c;那么Linux作为一个开源平台&#xff0c;最终要实现的是…

uniApp微信支付实现

后端&#xff1a;小程序下单 - 小程序支付 | 微信支付商户文档中心 服务端需要请求&#xff1a;https://api.mch.weixin.qq.com该地址获取微信支付Api接口需要的参数。 服务端请求接口需要的Body参数&#xff1a; 客户端&#xff08;前端&#xff09;需要调用&#xff1a;wx.…

12V降3.3V100mA稳压芯片WT7133

12V降3.3V100mA稳压芯片WT7133 WT71XX系列是一款采用CMOS工艺实现的三端高输入电压、低压差、小输出电流电压稳压器。 它的输出电流可达到100mA&#xff0c;输入电压可达到18V。其固定输出电压的范围是2.5V&#xff5e;8.0V&#xff0c;用户 也可通过外围应用电路来实现可变电压…