【C++初阶】四、类和对象(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)

news2024/11/17 5:54:08

=========================================================================

相关代码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.coloradmin.cn/o/1246242.html

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

相关文章

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

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

学习视频剪辑方法:AI智剪助力,批量处理短视频无忧

随着短视频的兴起&#xff0c;越来越多的人开始关注如何有效地制作和发布这些内容。但是&#xff0c;短视频的制作并不容易&#xff0c;要耗费大量的时间和精力。现在有很多AI智能剪辑工具可以快速、高效地制作短视频。其中&#xff0c;AI智剪是一款非常受欢迎的视频剪辑功能&a…

NX二次开发UF_CURVE_ask_arc_data 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_arc_data Defined in: uf_curve.h int UF_CURVE_ask_arc_data(tag_t arc, UF_CURVE_arc_p_t arc_coords ) overview 概述 Returns the data of an arc. The data is …

GCC lds 文件

文章目录 一、lds内部链接脚本参考资料ARM 编译器 一、lds 内部链接脚本 ld --verbose GNU ld (GNU Binutils for Ubuntu) 2.38支持的仿真&#xff1a;elf_x86_64elf32_x86_64elf_i386elf_iamcuelf_l1omelf_k1omi386pepi386pe 使用内部链接脚本&#xff1a;/* Script for -z …

SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、loadbalancer

文章目录 POM依赖环境准备配置配置文件配置类 案例展示 POM依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.10</version><relativePath/></p…

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…

wagtail-安装配置

系列文章目录 文章目录 系列文章目录安装虚拟环境安装wagtail查看安装后的包 创建wagtail项目安装依赖迁移创建超级用户运行项目 安装虚拟环境 https://blog.csdn.net/gsl371/article/details/117917857 安装wagtail (wagenv) C:\djproject\wagprj>pip list Package V…

编程入门基础知识,编程入门推荐,中文编程工具下载,软件定制开发

编程入门基础知识&#xff0c;编程入门推荐&#xff0c;中文编程工具下载&#xff0c;软件定制开发 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型…

【Git】一文教你学会 submodule 的增、删、改、查

添加子模块 $ git submodule add <url> <path>url 为想要添加的子模块路径path 为子模块存放的本地路径 示例&#xff0c;添加 r-tinymaix 为子模块到主仓库 ./sdk/packages/online-packages/r-tinymaix 路径下&#xff0c;命令如下所示&#xff1a; $ git subm…

SQL Server Profiler基础使用

文章目录 SQL Server Profiler基础使用简介如何打开直接打开Microsoft SQL Server Management Studio工具栏打开 配置跟踪新建跟踪跟踪属性配置常规配置事件选择 启动跟踪跟踪时执行脚本跟踪记录 暂停跟踪停止跟踪 SQL Server Profiler基础使用 简介 一个图形界面工具&#x…

创意设计与个性化定制:酒精壁炉的独特之处

在当今家居装饰的潮流中&#xff0c;人们越来越注重个性化和创意&#xff0c;而酒精壁炉正是在这一趋势中崭露头角。它不仅成为家居的温馨之选&#xff0c;更因其设计的灵活性而成为创意焦点&#xff0c;吸引了越来越多注重家居设计的人群。 酒精壁炉的设计灵活性为家居注入了新…

提供电商数据|带你简单认识天猫API接口相关参数文档调用说明

什么是API接口 API接口(Application Programming Interface Interface)是应用程序与开发人员或其他程序互相通信的方式。它允许开发者访问应用程序的数据和功能。 API接口,软件的“握手”与“交流”之道,软件世界的“好基友”。想让软件聊得来?想开发App却无从下手?API来相救…

Netty实现websocket且实现url传参的两种方式(源码分析)

1、先构建基本的netty框架 再下面的代码中我构建了一个最基本的netty实现websocket的框架&#xff0c;其他个性化部分再自行添加。 Slf4j public class TeacherServer {public void teacherStart(int port) throws InterruptedException {NioEventLoopGroup boss new NioEve…

视频录制工具有哪些?收藏起来,需要的时候用起来

视频录制工具顾名思义&#xff1a;用于捕获视频片段的软件。使用视频录制工具&#xff0c;你可以创建属于自己的视频内容。市面上的录屏工具五花八门&#xff0c;有哪些才是适合自己的呢&#xff1f; 虽然有许多视频录制工具可供选择&#xff0c;甚至有很多是免费的&#xff0…

Linux使用宝塔面板+Discuz+cpolar内网穿透工具搭建可公网访问论坛

Linux宝塔面板搭建Discuz论坛&#xff0c; 并内网穿透实现公网访问 文章目录 Linux宝塔面板搭建Discuz论坛&#xff0c; 并内网穿透实现公网访问前言1.安装基础环境2.一键部署Discuz3.安装cpolar工具4.配置域名访问Discuz5.固定域名公网地址6.配置Discuz论坛 前言 Crossday Di…

圈子社交系统丨论坛丨实名认证丨语音聊天丨VIP会员丨活动报名丨商城丨APP小程序h5丨源码交付,支持二开

圈子社交系统丨论坛丨实名认证丨语音聊天丨VIP会员丨活动报名丨商城丨APP小程序h5 后端下载地址&#xff1a;圈子系统APP源码&#xff0c;婚恋小程序&#xff0c;APP&#xff0c;H5&#xff0c;表白墙源码&#xff0c;恋爱小程序APP&#xff0c;交友APP小程序&#xff0c;社交小…

多线程 02

1.线程的常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用 Runnable 对象创建线程对象Thread(String name)创建线程对象&#xff0c;并命名Thread(Runnable target, String name)使用 Runnable 对象创建线程对象&#xff0c;并命名【了解】Thread(Threa…

数据库实验7

实验报告&#xff08;七&#xff09;数据更新 1、实验目的 &#xff08;1&#xff09; 掌握插入、更新和删除表数据的方法 &#xff08;2&#xff09; 掌握更新操作与子查询结合的用法 2、实验预习与准备 &#xff08;1&#xff09; Update&#xff0c;Delete&am…

内网横向技术

如果拿下了一台机器之后寻找域控机器 ipconfig /all 找到域名 ping 域名或者nslookup域名

拼多多平台全面API接口对接

对接流程&#xff08;支持虚拟商品&#xff09; 拼多多与商家之间数据双向请求&#xff0c;同步更新及相关数据传输。对接主要分为三大部分&#xff1a;准备阶段、对接测试、上线使用&#xff1b;针对每部分具体说明如下&#xff1a; 接口连通性测试重点关注两类接口的连通性&a…