【深度解析C++之初始化列表】

系列文章目录

        欢迎大家订阅我的《计算机底层原理》、《深度解析C++》系列专栏、我会持续为大家输出优质文章,能够帮助到大家就是对我最大的鼓励!😊


目录

系列文章目录

前言

一、什么是初始化列表

1.语法结构

2.为什么要使用初始化列表

1.效率:

2.成员常量变量和引用

        1.常量成员变量

        2.引用成员变量

        3.对象成员

 二、使用场景和实例

1.常规成员变量初始化

2.对象成员变量初始化

3.成员常量或者引用初始化

三、注意事项

1、成员变量初始化顺序:

2、避免使用未初始化的成员变量:

3、常量成员变量:

4、引用成员变量:

总结


前言

        这篇文章主要为大家讲解C++当中的初始化列表,这部分知识作为C++当中最基础的部分,虽然不难但是很容易被同学们忽略,C++毕竟是贴近操作系统底层的语言,很多语法内容是需要我们去理解的,不能单纯地死记硬背,例如为什么初始化列表就一定高效呢?有些变量为什么一定要使用初始化列表呢?再比如内联函数为什么可以节约系统开销呢?这些知识点你真的理解了吗?如果我们一味地依靠记忆学习编程的话,将会非常的吃力,各位小伙伴可以去翻阅一下我之前的文章,相信大家一定会有收获!


一、什么是初始化列表

1.语法结构

        初始化列表是在构造函数对类的成员变量进行初始化的工具,初始化列表是在C++中用于在构造函数中初始化成员变量的一种机制。它是在构造函数的参数列表后,构造函数体之前的部分,通过冒号(:)引入的。

ClassName::ClassName(parameters): member1(value1), member2(value2), ... {// 构造函数体
}

2.为什么要使用初始化列表

1.效率:

        初始化列表允许直接初始化成员变量,这个过程会在对象创建的过程直接完成,如果我们在构造函数的函数体当中进行赋值操作的话效率不如直接使用初始化列表,因为对象的创建通过调用new这个关键字来创建,首先对象创建好之后,new关键字会为这个对象分配空间,并且自动调用构造函数进行对这个对象的初始化,然后返回这个对象的地址。

        可是如果我们使用初始化列表的话,在对象创建的那一刻对象的成员变量就完成了初始化的操作,效率大大提升。那么为什么会这样呢?其实很好理解初始化列表定义在了构造函数函数体之前,所以初始化列表对这个对象进行初始化的时候,准确地来说这个时候构造函数还没有调用,而且初始化列表的初始化顺序取决于变量在类当中的声明顺序,和初始化列表当中的初始化顺序无关。这一点非常重要!

        如果文字的力量不够深刻的话,下面我是用代码来为大家进行解读,当我们创建一个对象的时候,对象的成员变量需要被赋予初始值,在C++当中我们可以使用构造函数来执行这一步操作,我们有两种方法,一是构造函数体内逐一赋值,二是使用初始化列表那么为什么使用初始化列表就一定更高效呢?请看代码。

class MyClass {
public:int x;double y;MyClass(int a, double b) {x = a;y = b;}
};

        如果我们定义了这样一段代码,那么进行对象初始化的时候就会进行如下操作:

        1)利用new关键字进行内存的分配

        2)new这个关键字会自动调用构造函数来为对象当中的字段进行初始化

        但是当我们使用初始化列表的时候

MyClass(int a, double b) : x(a), y(b) {}

        这种方式的好处在于直接创建对象的时候就已经完成了初始化,就像我刚才所说的一样,对象创建好的一瞬间就已经完成了初始化,就不需要再调用构造函数进行逐一初始化了,这里大家可能会有一个误区认为初始化列表是构造函数的一部分,这是大错特错的!!!它们两个虽然在语法结构上定义在了一起,但是其实它们是两个独立的过程,初始化列表对对象进行初始化的时候,构造函数还没有真正地开始执行呢!所以我们可以思考一下,我们不需要调用构造函数就能够为对象进行初始化了,你说这是不是高效呢?

2.成员常量变量和引用

        对于某些情况下的成员变量,例如常量或者引用,必须使用初始化列表进行初始化,不能够在构造函数的函数体内进行赋值初始化。

        1.常量成员变量

        常量成员变量是在声明的时候就被赋予初始值的,并且一旦被赋值就不能够在被修改,所以自然而然地也就不能够再函数体内进行赋值运算,因为一旦进入构造函数体常量成员变量就不能够再被修改。

 x;MyClass(int a) {// 错误:常量成员变量不能在构造函数体内赋值x = a;  }
};
        2.引用成员变量

        引用成员变量必须再构造函数的初始化列表当中进行初始化,一旦引用被初始化,它将一直引用同一个对象,无法在构造函数体内重新赋值为另一个对象,如果我们尝试在构造函数体内对引用变量进行赋值,编译器就会报错。

class MyClass {
public:int& y;// 错误:引用成员变量必须在初始化列表中初始化MyClass(int a) {y = a;}
};

        总结一下,常量和应用之所以只允许使用初始化列表进行初始化就是因为编译器不允许程序员在构造函数体内对他们进行操作,因为这些成员都不允许被修改,如果允许程序员在构造函数体内对他们进行操作的话,很有可能会引发很多的语义错误、和不必要的麻烦,所以编译器强制规定这些成员必须使用初始化列表进行初始化,不允许程序员对他们在构造函数体内进行额外的危险操作。

        3.对象成员

        大家可以观察下面的代码,对象成员必须使用初始化列表进行初始化,因为如果我们不在初始化列表当中对这个对象和进行初始化的话,那么Date类的构造函数会自动去调用_t 的默认构造函数来进行初始化,但是这个时候Time类没有默认构造函数,编译器就会报错引发未定义行为。所以初始化对象成员要么自动调用默认构造函数,如果没有默认构造函数的话,就必须使用初始化列表进行初始化

        这里有一很重要的一点,就是默认构造函数是什么?可能很多的小伙伴不明白,C++当中的默认构造函数一共有三类一类是我们不写编译器自动为我们生成的,另一类是无参构造函数再一类是全缺省参数的构造函数都叫做默认构造函数,当我们显示地定义了构造函数编译器就不会为我们生成默认构造函数了,除非我们自己写一个默认构造函数,所以这个时候对象成员初始化的时候如果要依靠编译器自动调用它的默认构造函数,他必须有默认构造函数才可以。如果没有的话那么就必须在初始化列表当中进行初始化才可以。

class Time {
public:int _hour;int _minute;int _second;// 构造函数Time(int hour, int minute, int second): _hour(hour), _minute(minute), _second(second) {// 构造函数体}
};class Date {
private:Time _t;public:// 使用初始化列表调用 Time 类中的构造函数Date(int hour, int minute, int second): _t(hour, minute, second) {// 构造函数体}
};


 二、使用场景和实例

1.常规成员变量初始化


private:int _a;double _b;public:// 使用初始化列表初始化成员变量Example(int a, double b) : _a(a), _b(b) {// 构造函数体}
};

2.对象成员变量初始化

class Time {
public:int _hour;int _minute;int _second;// 构造函数Time(int hour, int minute, int second): _hour(hour), _minute(minute), _second(second) {// 构造函数体}
};class Date {
private:Time _t;public:// 使用初始化列表调用 Time 类中的构造函数Date(int hour, int minute, int second): _t(hour, minute, second) {// 构造函数体}
};

3.成员常量或者引用初始化

class Example {
private:const int _constantValue;int& _referenceValue;public:// 构造函数初始化列表Example(int constantValue, int& referenceValue): _constantValue(constantValue), _referenceValue(referenceValue) {// 构造函数体}
};


三、注意事项

1、成员变量初始化顺序:

        初始化列表中的成员变量初始化顺序与它们在类中声明的顺序有关,而不是出现在初始化列表中的顺序。

2、避免使用未初始化的成员变量:

        在初始化列表中确保所有成员变量都被初始化,避免使用未初始化的成员变量,尤其是对于常量和引用成员。

3、常量成员变量:

        常量成员变量必须在初始化列表中进行初始化。

4、引用成员变量:

        引用成员变量必须在初始化列表中与某个对象绑定。初始化列表是C++中一个重要的概念,尤其在构造函数中的使用,它可以提高代码的效率,同时确保对象在被创建时具有正确的初始状态。


总结

        C++当中的初始化列表就为大家讲解到这里,希望读完这篇文章大家已经能够彻底搞懂初始化列表到底是怎么一回事了,希望大家读我的文章能够所有收获!

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

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

相关文章

LeetCode 2974. 最小数字游戏

你有一个下标从 0 开始、长度为 偶数 的整数数组 nums ,同时还有一个空数组 arr 。Alice 和 Bob 决定玩一个游戏,游戏中每一轮 Alice 和 Bob 都会各自执行一次操作。游戏规则如下: 每一轮,Alice 先从 nums 中移除一个 最小 元素&…

Vue-Pinina基本教程

前言 官网地址:Pinia | The intuitive store for Vue.js (vuejs.org) 看以下内容,需要有vuex的基础,下面很多概念会直接省略,比如state、actions、getters用处含义等 1、什么是Pinina Pinia 是 Vue 的存储库,它允许您跨…

AI一叶知秋:从目标检测部署浅谈人工智能发展

笔者写这篇文章也有讨巧之嫌,仅以个人视角分享一些看法,主要从实践部署来谈谈近两年来计算机视觉模型的变化,不过AI是一个宏大的话题,每个人定义的人工智能就不一样,我们先来探讨一下何为人工智能。百度百科中是这样定…

〖Python网络爬虫实战㊹〗- JavaScript Hook 的用法

订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 说明:本专栏持续更新中,订阅本专栏前必读关于专栏〖Python网络爬虫实战〗转为付费专栏的订阅说明作者&#xff1…

buuctf-Misc 题目解答分解97-99

97.[BSidesSF2019]zippy 下载完就是一个流量包 追踪tcp nc -l -p 4445 > flag.zip unzip -P supercomplexpassword flag.zip Archive: flag.zip 压缩包密码 supercomplexpassword 保存为 flag.zip 解压得到flag 98.[GUET-CTF2019]虚假的压缩包 先从虚假的压缩包入手 &am…

MySQL的事务-隔离级别

上篇,整理了MySQL事务的原子性,这篇继续整理MySQL事务的一致性、隔离性和持久性。 2. 一致性指的是事务开始前和结束后,数据库的完整性约束没有被破坏,这保证了数据的完整性和一致性。一致性必须确保数据库从一个一致的状态转换到…

数据结构-算法概念与程序设计

目录 一、算法 二、算法设计的要求 三、如何去衡量不同算法之间的优劣 一、算法 概念:算法是对于特定问题求解步骤的一种描述,是指令的有限序列,其中每一条质量表示一个或者多种操作,具有以下特性: (1&…

C++ 比 C语言的新增的特性 1

1. C是C的增强 1.1 C是静态类型的语言,具有严格的数据类型检查 1.1.1 c 因为const修饰的变量不允许修改,但是只给了警告,不严谨 const int a10;a20; //报错int *p&a;*p20;//a的值? test1.c:6:9: warning: initialization dis…

详解Java反射机制reflect(一学就会,通俗易懂)

1.定义 #2. 获取Class对象的三种方式 sout(c1)结果为class com.itheima.d2_reflect.TestClass 获取到了Class对象就相当于获取到了该类 2.获取类的构造器 3.获取全部构造器对象 2.根据参数类型获取构造器对象 类型后必须加.class 3.构造器对象调用构造器方法 4.暴力访问 4.获…

【笔记】入门PCB设计(全30集带目录) 杜洋工作室 AD09 Altium Designer

入门PCB设计(全30集带目录) 杜洋工作室 AD09 p1 创建p2 原理图上增加元件1)加元件2)放导线3)自定义元件1. 自定义排针2.有引脚的元件 p3 完整原理图 p1 创建 step1.创建(PCB)工程,后缀.PrjPCB。…

【FPGA 器件比较】Altera -- Xilinx

比较以下市场前二名的产品线及定位 应用场景XilinxAltera高性能VersalAgilex F/I性能Virtex / Kintex / Artix / Zynq UltraScaleAgilex F/I / Stratix 10中档Virtex / Kintex / Zynq ~ 7 / UltraScaleStratix 10 / Arria 10低成本Artix-7 Sparton-7Cyclone 10 如上表&#x…

Linux构建NFS远程共享存储和ftp配置

NFS架构 NFS介绍 文件系统级别共享(是NAS存储) --------- 已经做好了格式化,可以直接用。 速度慢比如:nfs,samba NFS:Network File System 网络文件系统,NFS 和其他文件系统一样,是在 Linux …

《Git快速入门》Git分支

1.master、origin、origin/master 区别 首先搞懂git分支的一些名称区别: master : Git 的默认分支名字。它并不是一个特殊分支、跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它&#xff0c…

Redis缓存穿透、缓存击穿、缓存雪崩介绍

一、Redis的缓存穿透 1.什么是缓存穿透? 缓存穿透是指:客户端请求的数据在缓存中和数据库中都不存在,这时缓存就永远不会生效,这些请求都打到数据库从而导致数据库压力过大。 2.出现缓存穿透的解决方案,以下是常用的两…

C语言第五十九弹---介绍说明内存函数memcmp

使用C语言介绍说明内存函数memcmp memcmp是C语言标准库中的一个函数,用于比较两个内存区域的内容是否相同。 源代码: int memcmp(const void* ptr1, const void* ptr2, size_t num);ptr1和ptr2分别是要比较的两个内存区域的指针,num是要比较…

es检索之复合检索

背景:向量检索是文本相似度检索,现在增加新的字段进行过滤,如果以filter方式进行过滤,那么最终结果不保证有topK个,甚至一个都没有,因为它是先进行topK个向量召回,再进行filter。 当然有人建议采用scriptScore方式进行检索,但此方式可能造成请求压力过大,内存消耗。 …

reactor的原理与实现

网络模型 前情回顾服务器模型 Reactor和 ProactorReactor模型Proactor模型同步I/O模拟Poractor模型Libevent,libev,libuv优先级事件循环线程安全 前情回顾 网络IO,会涉及到两个系统对象:   一个是用户空间调用的进程或线程   …

自媒体实战篇:作品爆款三要素的使用场景和重要性

作品爆款三要素的使用场景和重要性 什么是爆款三要素 标题 概括视频内容,吸引用户注意封面 吸引眼球,引发作者联想标签 精准分类,有利于平台精准推流优质标题要求 标题就是介绍视频故事内容的一段话,通常分为三段式注册,统称三段式标题好的标题统称是三段式的,即点明故事…

C均值算法例子

有如下数据,试使用C-均值聚类将该数据集聚为2类。初始聚类中心为P1和P2,写出计算过程。 坐标点XYP100P212P331P488P599P6107 解:6个点聚离P1,P2的距离分别如下: ( 0 , 5 , 10 , 8 2 , 9 2 , 149 (0, \sqrt 5,\sqrt {…

07 Vue3框架简介

文章目录 一、Vue3简介1. 简介2. 相关网站3. 前端技术对比4. JS前端框架5. Vue核心内容6. 使用方式 二、基础概念1. 创建一个应用2. 变量双向绑定(v-model)3. 条件控制(v-if)4. 数组遍历(v-for)5. 绑定事件…