C++语言·类和对象(下)

1. 初始化列表

        我们回忆上节写的MyQueue类,其中有两个栈类和一个int类型,栈类因为其特殊性,要开空间,所以我们必须手搓Stack类的构造函数。但是正常来说MyQueue自动生成的构造函数会调用自定义类型的默认构造函数,也就是说我们不必再手搓MyQueue类的构造函数了,编译器自动生成的就好用。

        但是此时问题来了,默认构造函数简单点理解就是不用传参就能调用的构造函数,那么如果我们手搓的Stack类没有默认构造函数,那么MyQueue就不能自动生成构造函数了,因为它没得调了,就像这样。

                

        光标圈出来的那一行中,我们没有给构造函数搞缺省参数,所以它必须传参才能调用,也就是说此时Stack类没有了默认构造函数,那么现在编译器是处在报错的状态,那我们如何通过写MyQueue的构造函数来解决这一问题。

        此时就要说到初始化列表的概念了,初始化列表本质上可以理解成每个对象中成员定义的地方,所有成员你可以在初始化列表初始化,也可以在函数体内部初始化。

        具体写法就是:以一个冒号开始,接着是一个以逗号分开的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式。

                        

        ps: 这里面size其实应该前面有个下划线的,但是我忘记写了,大家凑活着看吧

        _pushst 和 _popst 的初始化必须要在函数体外面写,因为他俩进了函数体就没法初始化了呀,不过size初始化可以写到函数体里头,当写在函数体里头的时候有必须要用赋值的方案进行初始化了。

        虽说类中的所有成员都可以在初始化列表和函数体内初始化,但是有三类成员必须在初始化列表中初始化:1. 引用        2. const成员        3. 没有默认构造的自定义类型成员

        我们知道如果在定义成员变量的时候赋值,我们管这个行为叫给成员变量缺省值,这个缺省值的含义就是为了给初始化列表的缺省值。因为初始化列表不管你有没有显式写,编译器都会自动给每个成员都走一遍,自定义类型的成员会调用其默认构造函数,内置类型就不做操作(除非有缺省值,那么编译器的行为相当于自动在括号中写那个缺省值)。这就解释了上面Stack没有默认构造函数MyQueue就不能自动生成构造函数。

        既然是缺省值,我们在显式写初始化列表的时候就可以更改,同时默认构造函数那个赋的不也是缺省值嘛,因此也可以更改。

                ​​​​​​​        

        这里强调一下,缺省值是可以给表达式的,比如我们可以给一个指针成员一个malloc缺省值。

        那么函数体中的语句的优先顺序比初始化列表还要高,也就是说初始化列表中已经初始化好的成员我们还可以在函数体中进一步修改。具体优先顺序就是: 缺省值 < 初始化列表 < 函数体

        成员变量在类中声明次序就是其在初始化列表中的初始化顺序,初始化顺序与其在初始化列表中的先后次序无关。我们看下面这段代码的输出就懂了

        ​​​​​​​        

        因为是先初始化的_a2所以输出的不是两个1,而是1和随机值。

        最后在实践中,尽可能使用初始化列表进行初始化,不方便再用函数体初始化。

2. 对象赋值时的隐式类型转换

        我们看下面这一段代码

                        ​​​​​​​​​​​​​​

        我们知道aa1通过构造函数赋值,aa2通过拷贝构造赋值,那aa3是怎么回事?raa又是怎么回事?

        aa3这里其实产生了隐式类型转换,由内置类型转换为了自定义类型。首先3先构造一个A类型的临时对象,再用这个临时对象拷贝构造aa3。所以说单参数构造函数可以支持这种直接赋内置类型的操作,它会产生隐式类型转换。现在我们在看打印出来的结果,当 3 赋给 aa3 的时候只调用了构造函数,这是因为编译器遇到 连续构造+拷贝构造 的组合时会优化成直接构造.

        raa的本意是取引用,首先 3 先隐式转换出来一个临时对象,为了权限不放大,所以要给const,之后raa引用3转换出来的这个新的临时对象。所以只有 3 隐式转换的时候出现了构造函数,没有拷贝构造出现。

        这个隐式类型转换的意义就是在于能够简化我们的代码量,有时还能缩减运行效率,直接赋一个内置变量,让编译器自己去类型转换。比如说我们想往栈里头压这个A类对象:

        ​​​​​​​        ​​​​​​​        

        我们可以选择先构造一个对象,然后再给到压栈。或者直接不写构造了,直接压1,让编译器自己类型转换去,这不就方便多了。

        上面是单参数的隐式类型转换,那多参数的写法是这样的:

        ​​​​​​​        ​​​​​​​        

        给值的时候用花括号括起来,写不写等于号都行,但是推荐写上等于号,这样和普通括号有点区别。

2.1 explicit关键字

        如果不想让构造能发生隐式类型转换,就在构造函数前面加上explicit关键字就行,单参数和多参数通用的。

        ​​​​​​​        ​​​​​​​        ​​​​​​​​​​​​​​

        aaa1因为隐式类型转换被拒所以无法构造了,那个aaa2没报错是因为编译器在这里把花括号当括号处理了。我们看aaa掉成员函数时的情况,传对象的时候就通过了,但是尝试传内置类型的时候隐式类型转换被拒绝了,因此编译报错。

3. static 静态成员

        声明为static的类的成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员函数一定要在类外进行初始化。

        静态成员有如下特性:

        1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。

        2. 静态成员变量必须定义在类外定义,定义时不添加static关键字,类中只是声明

        3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员访问

        4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

        5. 静态成员也是类的成员,受 public,protected,private 访问限定符的限制

        ​​​​​​​        ​​​​​​​        

        我们看上面一段代码。

        _scount是一个静态成员变量,这里我将它开放成了public,否则无法在类外访问。它存储于静态区,并属于所有的A类和其实例(对象),也就是说它可以直接通过类 A::_scount 访问,同时从任何地方访问(通过类访问,或通过对象访问)并改变其值的操作,都会直接改变其在静态区存储的值,也就是说任何依次改变都会影响A类以及其下所有实例中的_scount值,这就是所谓的静态成员变量属于所有类对象。同时因为它存储于静态区,所以在实例化类的时候静态成员变量同成员函数一样,不占用对象的空间。

        _scount在类中声明的时候不能给缺省值,给了就报错,因为给缺省值是为了在初始化列表中初始化,但是_scount不走初始化列表,它是静态变量,因此必须在类外定义

        那么这个静态成员变量可以用来干嘛呢,举个例子,它可以实时检测该类存在几个实例化对象,因为创建对象无非两种方法,构造和拷贝构造,因此我显式写每执行依次这两种构造就++_scount ,对象销毁析构的时候再 --_scount。最终打印出来的效果还是挺明显的。

        我们再看下一段代码,讲解一下静态成员函数

        ​​​​​​​        ​​​​​​​        ​​​​​​​

        这里我将_scount设置为private状态了,那么此时就不能再类外访问它了,也就是说无法这样 A::_scount 访问了,当然这也比较符合我们写成员变量的习惯,就是把所有成员变量都设置成private状态加以保护。那此时我们就要通过静态成员函数访问。static修饰变量和修饰函数的意义完全不一样,修饰变量时改变了变量的声明周期,修饰函数时改变了它的链接属性。那么静态成员函数的特性就是没有this指针,也就是说静态成员函数只能访问静态成员变量。

        那么使用的时候跟静态成员函数很像,既可以通过类访问,也可以通过对象访问得到_scount的值

4. 友元

        友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

        友元分为友元函数和友元类:

4.1 友元函数

        在上节重载流插入和流提取的时候,我们为了保证传参顺序符合习惯,因此将流插入和流提取的重载函数写在了类外,从而引发了无法访问private成员变量,当时我们给出的解决方案是写Get函数,取消private状态肯定是不可取的,要不我们还封装个什么。

        那么本节我们可以通过友元函数的设置来打破针对某一个函数的封装,其实上节最后实现日期类的时候我就已经搞友元了不知道大家注意到了没有。

                

        这里我把日期类简化了一下,就保留了流插入和流提取的内容,在类刚开始那两行用friend修饰的代码就是友元函数的修饰,用一个friend关键字修饰一个外部函数的声明,就能使这个外部函数访问类内部的private信息了。

4.2 友元类

        跟友元函数类似,在一个类中声明另一个类是友元的,那么就可以在另一个类中访问这个类的私有信息。形象一点来说就是:你是我的朋友,那么你就可以知道我的一些私有信息。

        ​​​​​​​        ​​​​​​​        

        B中可以访问A中的私有成员,但是A不能访问B的成员。

        最后还要说一下友元不能传递,就比如C是B的友元,B是A的友元,但是C不是A的友元。也就是说,A不能访问C的私有成员。

5. 内部类

        如果一个类定义在另一个类的内部,这个内部的类就叫做另一个类的内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的私有成员。外部类对内部类没有任何优越的访问权限。

        内部类天生是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但是外部类不是内部类的友元

        说白了就是外部类和内部类就是两个几乎完全平行的两个类,唯一不同的就是内部类要受到类域的限制,使用时必须在外部类类域下使用,同时内部类天生是外部类的友元。

        ​​​​​​​        ​​​​​​​        ​​​​​​​

6. 匿名对象

        匿名对象就是在实例化的时候不给名字,它的生命周期只在当前这一行,即用即销毁

        ​​​​​​​        ​​​​​​​        

7. 拷贝对象时的一些编译器优化

        因为我的编译器是vs2022优化开的太大了,没办法演示,就简单描述一下了。优化的话如果在Debug版本下,一定是在一行代码中进行优化的。但是如果开成release版本就有可能产生跨行优化。我下面讲的都是在Debug版本下的编译器优化方案。

        隐式类型:连续构造+拷贝构造 -> 优化成直接构造

        传值返回:拷贝构造+拷贝构造 -> 优化为一个拷贝构造,这里有一个值得注意的点,就是拷贝构造+赋值运算重载是无法优化的

        

        

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

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

相关文章

基于SpringBoot+Vue的体检管理系统 免费获取源码

项目源码获取方式放在文章末尾处 项目技术 数据库&#xff1a;Mysql5.7/8.0 数据表&#xff1a;12张 开发语言&#xff1a;Java(jdk1.8) 开发工具&#xff1a;idea 前端技术&#xff1a;vue html 后端技术&#xff1a;SpringBoot 功能简介 (有文档) 项目获取关键字&…

浏览器渲染流程中的 9 个面试点

记得 08 年以前&#xff0c;打开网页的时候一个页面卡死整个浏览器凉凉。 这是因为当时浏览器是单进程架构&#xff0c;一个页面或者插件卡死&#xff0c;整个浏览器都会崩溃&#xff0c;非常影响用户体验。 经过了一代代工程师的设计&#xff0c;现代浏览器改成了多进程架构&…

异常检测 | SVDD支持向量数据描述异常数据检测(Matlab)

异常检测 | SVDD支持向量数据描述异常数据检测&#xff08;Matlab&#xff09; 目录 异常检测 | SVDD支持向量数据描述异常数据检测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 用于一类或二元分类的 SVDD 模型 多种核函数&#xff08;…

医学临床预测模型发展新趋势-并联式

医学临床预测模型发展新姿势-并联式 现有的预测模型是对单个结局指标进行分类或者回归&#xff0c;得出最终的结论&#xff0c;而辅助医生进行临床决策。众所周知&#xff0c;临床决策过程中&#xff0c;医生通常会考虑多个结局指标来做出最终的决策&#xff1b;临床研究中也通…

网络编程初步

协议&#xff1a; 一组规则 分层模型结构&#xff1a; OSI七层模型&#xff1a;物、数、网、传、会、表、应 TCP/IP 4层模型&#xff1a;网&#xff08;链路层/网络接口层)、网、传、应 应用层&#xff1a;http、 ftp、 nfs、 ssh、 telneto o .传输层:TCP、UDP 网络层&…

【干货精品分享】Elasticsearch 6.7 Should 子语句的失效

在ES 使用多条件 查询&#xff0c;并且是多个条件只需要满足部分条件的时候&#xff0c;我们通常会使用到ES的should查询 GET /trademark_query_index/_search {"query":{"bool" : {"must":[{"match" : {"origin": {"…

229 基于matlab的网络入侵检测问题

基于matlab的网络入侵检测问题&#xff0c;主要使用有监督的Kohonen神经网络。有监督Kohonen神经网络的网络结构为38-36-5&#xff0c;网络训练结果受权值影响相当大。在算法初期&#xff0c;本文引入杂草算法对Kohonen网络进行权值寻优。文件包括&#xff1a;入侵数据(data.ma…

网站备案期间怎么关闭首页显示无法访问-文章及其它页面正常访问

自从做了开发者之后才发现每个人博主的需求都是不同的&#xff0c;的的确确颠覆了我的观点&#xff0c;无论是页面布局还是SEO相关的设置&#xff0c;可能是因为站点属性不同所以需求不同&#xff0c;慢慢的就会在主题加入一些自定接口来满足不同人的需求&#xff0c;有人需要P…

centos修改启动项加载不同内核

一.背景&#xff1a; 虚拟机中有时需要编译好几个内核版本&#xff0c;make install后系统存在几个内核版本。需要再哪个内核上开发调试就启动特定的内核版本。这就需要修改启动时的内核版本&#xff0c;再物理机或虚拟机启动时可以上下键选择。但有时是docket云环境中或远程时…

RK3568笔记二十二:基于TACO的垃圾检测和识别

若该文为原创文章&#xff0c;转载请注明原文出处。 基于TACO数据集&#xff0c;使用YOLOv8分割模型进行垃圾检测和识别&#xff0c;并在ATK-RK3568上部署运行。 一、环境 1、测试训练环境&#xff1a;AutoDL. 2、平台&#xff1a;rk3568 3、开发板: ATK-RK3568正点原子板子…

Tomcat源码解析——类加载机制

一、类加载器的创建 在之前的Tomcat启动源码中&#xff0c;简单的介绍了Tomcat的四种类加载器&#xff0c;再复习一遍。 类加载器 作用父加载器commonLoader&#xff08;共同类加载器&#xff09;加载$CATALINA_HOME/lib下的类加载器应用类加载器catalinaLoader&#xff08;容器…

Games101-光线追踪(辐射度量学、渲染方程与全局光照)

Basic radiometry (辐射度量学) 光的强度假定l为10&#xff0c;但是10是什么。 Whitted-Style中间了很多不同简化&#xff0c;如能看到高光&#xff0c;表示做了布林冯着色&#xff0c;意味着一个光线打进来后会被反射到一定的区域里&#xff0c;而不是沿着完美的镜像方向&…

html select 支持内容过滤列表 -bootstrap实现

实现使用bootstrap-select插件 http://silviomoreto.github.io/bootstrap-select <!DOCTYPE html> <html> <meta charset"UTF-8"> <head><title>jQuery bootstrap-select可搜索多选下拉列表插件-www.daimajiayuan.com</title>&…

【Git】常用命令速查

目录 一、创建版本 二、修改和提交 三、查看提交历史 四、撤销 五、分支与标签 六、合并与衍合 七、远程操作 一、创建版本 命令简要说明注意事项git clone <url>克隆远程版本库 二、修改和提交 命令简要说明注意事项 三、查看提交历史 命令简要说明注意事项 …

Ribbon 添加快速访问区域

添加快速访问区域挺简单的&#xff0c;实例如下所示&#xff1a; void QtRightFuncDemo::createQuickAccessBar() { RibbonQuickAccessBar* quickAccessBar ribbonBar()->quickAccessBar(); QAction* action quickAccessBar->actionCustomizeButton(); act…

最邻近插值和线性插值

最邻近插值 在图像分割任务中&#xff1a;原图的缩放一般采用双线性插值&#xff0c;用于上采样或下采样&#xff1b;而标注图像的缩放有特定的规则&#xff0c;需使用最临近插值&#xff0c;不用于上采样或下采样。 自定义函数 这个是通过输入原始图像和一个缩放因子来对图像…

[NISACTF 2022]huaji?

注意要加--run-asroot

基于ThinkPHP框架开发的的站长在线工具箱网站PHP源码(可以作为流量站)

这是一套基于ThinkPHP框架开发的站长在线工具箱网站PHP源码&#xff0c;包含了多种在线工具&#xff0c;可以作为流量站使用。 项 目 地 址 &#xff1a; runruncode.com/php/19742.html 部署教程&#xff1a; 环境要求&#xff1a; - PHP版本需要大于等于7.2.5 - MySQL版…

2024年适用于 Android 的最佳免费数据恢复应用程序

无论是系统崩溃、软件升级、病毒攻击还是任何其他故障&#xff0c;这些软件问题都可能导致手机上的数据丢失。可以使用免费的数据恢复应用程序修复数据故障并检索丢失或删除的文件。 数据恢复应用程序旨在从另一个存储设备中检索丢失或无法访问的数据。这些工具扫描 UFS 并尝试…

视频素材库哪里最好?8个视频素材免费商用

在视频创作的世界里&#xff0c;寻找那些能够完美匹配你的想法并加以实现的视频素材是一项既令人兴奋又充满挑战的任务。无论你的目标是提升视频质量、增强视觉效果&#xff0c;还是简单地想要让你的作品更加出色&#xff0c;这里有一系列全球精选的视频素材网站&#xff0c;它…