21天学会C++:Day12----初始化列表
· CSDN的uu们,大家好。这里是C++入门的第十一讲。
· 座右铭:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:C++专题

目录
1. 初始化列表
1.1 引入
1.2 初始化列表
1.3 初始化列表的注意事项
1.4 初始化列表成员变量的初始化顺序
2. 同一表达式连续构造的优化
3. 静态成员变量与静态成员函数
4. 内部类
1. 初始化列表
1.1 引入
还记得我们之前在学习类和对象的时候是怎么给类的成员变量 "初始化" 的吗?我们是通过构造函数在函数体内部给成员变量赋值的。为什么说是赋值而不是说初始化呢?因为成员变量的初始化就不是在函数体内部完成的!而是一个叫初始化列表的东西中完成的!
我们定义了一个类A,在构造函数中我们对成员变量进行了多次赋值!以此来证明构造函数的函数体不是对成员变量进行初始化的地方。
class A
{
public:A(int x = 0, int y = 0){_x = x;_x = 5;_y = y;}
private:int _x;int _y;
};int main()
{A a(2, 3);return 0;
}
1.2 初始化列表
我们先来看看初始化列表的语法吧:
以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
比如下面的代码:
class A
{
public:A(int x = 0, int y = 0):_x(x),_y(y + x){}
private:int _x;int _y;
};
在括号里面也是可以写表达式的哦!
我们的C++祖师爷为什么要设计出初始化列表呢?那肯定是因为函数体内的赋值无法对所有类型的成员变量进行赋值。我们来看下面的代码:

我们看到类的成员变量如果有const 修饰的变量或者引用,在构造函数的函数体内部赋值就会直接报错了!根据报错提示,我们也能够隐隐猜到构造函数的函数体不是成员变量初始化的地方!
对于const修饰的变量 和引用都有一个共同的特性:在定义的时候必须初始化!我们又知道了初始化列表才是成员变量真正定义的地方!所以const 修饰的变量和引用就必须在初始化列表中初始化:这样的代码就没有什么问题啦!
class A
{
public:A(int x = 0, int y = 0):_x(x),_y(y){}
private:const int _x;int& _y;
};
1.3 初始化列表的注意事项
我们来看看初始化列表的注意事项:
1:每个成员变量在初始化列表中最多出现一次。
2:类中包含以下成员,必须放在初始化列表位置进行初始化: 引用成员变量 const成员变量 自定义类型成员,且该类没有默认构造函数时。
我们来看第一点:每个成员变量在初始化列表中最多出现一次。我们现在知道了初始化列表是成员变量定义的地方。如果一个成员变量在初始化列表中出现两次,那么这个变量不就是被定义了两次嘛!这当然是不被允许的!

第二点: 引用变量 与 const 修饰的成员变量为什么只能在初始化列表中初始化你应该已经明白了!那么没有默认构造函数的自定义类型为什么也必须要在初始化列表中初始化呢?
你还记得默认构造函数的定义嘛:默认构造函数就是不用传参就可以直接调用的构造函数。
来看下面的代码:我们定义了类A,自己写了带参的构造函数,那么编译器则不会为类A提供默认构造函数。我们又定义了类B,成员变量是自定义类型。我们尝试在B的构造函数中给成员变量赋值。
class A
{
public:A(int x, int y):_x(x),_y(y){}
private:int _x;int _y;
};class B
{
public:B(A a){_a = a;}private:A _a;
};
我们编译器直接报错了:类 A 不存在默认构造函数!为什么会报这个错误呢?我们知道初始化列表是成员变量定义的地方,那么类B的成员变量会在初始化列表中有类似这样的定义:A _a。即在定义的过程中他会去调用A的默认构造函数,但是因为 A 没有默认构造函数自然就会报错了!
也就是说:对于自定义类型的成员变量,如果该成员变量没有显示在初始化列表中初始化, 就会调用该自定义类型的默认构造函数。
那如果我们在初始化列表中显示初始化,就会调用对应的构造函数对自定义类型的成员变量进行初始化。

1.4 初始化列表成员变量的初始化顺序
先不着急讲解知识点,我们来看看下面的代码的输出结果是什么?
class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}private:int _a2;int _a1;
};int main()
{A aa(1);aa.Print();return 0;
}
A:输出 1 1
B:程序崩溃
C:编译不通过
D:输出 1 随机值
答案是D哦!初始化列表的初始化顺序并不是按照初始化列表中的书写顺序来的!而是按照成员变量的声明顺序来的!_a2先声明,那么就会先初始化_a2,因此_a2用还未初始化的_a1初始化就是随机值。所以说为了避免出现这样的错误,初始化列表的书写顺序最好与成员变量的声明顺序一致。
最后一点:还记得我们在类中给成员变量缺省值的操作嘛!那个缺省值其实就是给初始化列表初始化的!
2. 同一表达式连续构造的优化
大家觉得下面的代码有没有问题呢?
class A
{
public:A(int x):_x(x){}A(const A& a){_x = a._x;}private:int _x;
};int main()
{A a = 2;return 0;
}
你变异之后发现变异通过并且运行良好!这是为啥呢?整形可以直接赋值给自定义类型?其实不是的啦!这其中发生了隐式类型转化,C++98的语法:单参数的构造函数支持隐士类型转换。所以说 A a = 2;其实是用 2 这个整形调用了A的构造函数,构造了一个A的对象,然后在通过拷贝构造来构造 a 这个对象!
如果你不能理解我们可以拿一个内置类型来举例:
我们有一个整形变量直接将他赋值给一个double变量,看看编译器是怎么做的。

这个道理和 A a = 2;是一样的撒!所以在这一个表达式中调用了构造函数和拷贝构造函数!于是编译器看不下去了!他将这个表达式优化成了直接调用构造函数来构造 a 这个对象。编译器是容忍不了一个表达式出现两个构造函数的调用的!
那你可能不相信我的解释,你说:有没有可能并没有一个临时对象被构造出来,而本来就是用 2 直接构造a这个对象。那我们来看看这个代码:A& a = 2; 报错:非常量引用的初始值必须为左值,也就是说,在给 a 赋值的时候,a引用的是一个右值,自然就报错了。

可是我们如果用的是const的引用呢?发现就没有报错了!我们知道临时对象具有常性,加上const才能对其进行引用。但是这也并不能说明通过2构造了一个A的对象哇!你可能会说a就是引用的2这个右值嘛!
OK,那很巧,C++中有一个关键字能够废除这种隐式类型转换:explicit。如果真如你所有说 a 能够引用 2 这个右值,那么废除 这种隐式类型转换也不会报错吧!

很遗憾他报错了!那么说明这种隐式类型转换是真实存在的!
3. 静态成员变量与静态成员函数
假设我们现在有这样一个需求,需要你统计出一个类实例化出了多少个对象!你激动的说到,这个我会呀!对象实例化不是都要调用构造函数吗,对象销毁不是都要调用析构函数嘛,那么我只要维护一个全局变量count,然后再构造函数里对count++,析构函数里面对count--,不就大功告成了吗?是的你很厉害,也很聪明!
int _count;class A
{
public:A(int x = 0):_x(x){_count++;}A(const A& a){_x = a._x;_count++;}~A(){_count--;}private:int _x;
};
可是有一天,来了一个程序员,看到了这个count,这是干什么用的?一下就给你把count给改了!显然不行!
原因还是在与全局变量无法得到有效的封转保护!于是我们的静态成员变量他来了!静态成员变量可以理解为全局变量的封转,使得变量更好被维护。静态成员变量应该怎么初始化呢?很简单:

class A
{
public:A(int x = 0):_x(x){_count++;}A(const A& a){_x = a._x;_count++;}~A(){_count--;}private:int _x;static int _count;
};
静态成员变量属于一个类,不单独属于任何一个对象!静态成员变量是所有对象共享的。访问静态变量的时候只要突破类域和访问权限就可以直接访问。可以通过类域,也可以通过对象访问。

但是吧静态成员变量设置为共有又有一点不太好!因此我们需要提供一个函数来访问静态成员变量。

我们提供了一个普通的成员函数,发现必须需要有对象才能访问这个函数!但是我们的需求是随时访问这个函数,因此我们将这个函数变为静态函数!静态函数没有this指针,不能访问非静态的成员变量(因为函数访问普通的成员变量就是通过this指针访问的嘛)。通过对象或者类名都可以直接访问。前提是有权限哦!

4. 内部类
内部类 概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
特性:
1. 内部类可以定义在外部类的public、protected、private都是可以的。
2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
3. sizeof(外部类) = 外部类,和内部类没有任何关系。
内部类C++用的不多,Java喜欢用内部类。内部类供大家了解一下吧!

相关文章:
21天学会C++:Day12----初始化列表
CSDN的uu们,大家好。这里是C入门的第十一讲。 座右铭:前路坎坷,披荆斩棘,扶摇直上。 博客主页: 姬如祎 收录专栏:C专题 目录 1. 初始化列表 1.1 引入 1.2 初始化列表 1.3 初始化列表的注意事项 1.…...
OpenAI开发系列(二):大语言模型发展史及Transformer架构详解
全文共1.8w余字,预计阅读时间约60分钟 | 满满干货,建议收藏! 一、介绍 在2020年秋季,GPT-3因其在社交媒体上病毒式的传播而引发了广泛关注。这款拥有超过1.75亿参数和每秒运行成本达到100万美元的大型语言模型(Large …...
Gson - 一个Java序列化/反序列化库
官网 GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back 项目简介 一个Java序列化/反序列化库,用于将Java对象转换为JSON和返回JSON。 Gson is a Java library that can be used to convert Java…...
6-1 汉诺塔
汉诺(Hanoi)塔问题是一个经典的递归问题。 设有A、B、C三个塔座;开始时,在塔座A上有若干个圆盘,这些圆盘自下而上,由大到小地叠在一起。要求将塔座A上的圆盘移到塔座B上,并仍按同样顺序叠放。在…...
Linux之initd管理系统(海思、ZYNQ、复旦微)添加密码登录验证
设置root用户密码:passwd命令设置密码,即修改/etc/passwd文件 一、串口提示输入用户名密码方法 修改 /etc/inittab 方法一: 增加: ::askfirst:-/bin/login 注释: #::respawn:/sbin/getty -L ttyS000 115200 vt…...
怎么更改代理ip,代理ip如何切换使用?
我们要如何使用HTTP代理,对它进行切换使用呢? 如果你购买了青果网络的HTTP代理,可以在文档这边获取使用方法: 可以在这里调试: 也可以在这里选择key提取。 如果有的朋友们想利用利用python,每隔30秒使用API…...
【C++从0到王者】第三十三站:AVL树
文章目录 前言一、AVL 树的概念二、AVL树的实现1. AVL树的结点定义2. AVL树的插入之插入部分3. AVL树的插入之平衡因子的改变4. AVL树的插入之左旋5. AVL树的左旋抽象图6.AVL树的右旋抽象图7. AVL树的双旋8. AVL树的右左双旋9. AVL树的右左双旋的本质10. AVL树的左右双旋11. AV…...
手机机型响应式设置2
window.screen.height:屏幕高度 window.innerHeight:视口高度(去除浏览器头尾的高度) document.body.clientHeight:内容高度 vh:网页视口高度的1/100 vw:网页视口宽度的1/100 vmaxÿ…...
uni-app 之 解决u-button始终居中问题
uView中u-button始终居中问题如何解决的简单方法? 1:给该元素margin-right: 0;可以达到向右靠齐; 2:给该元素的父元素设置float: right image.png <u-button style"width: 50px; margin-left: 0;" plain"t…...
Python日期处理库:掌握时间的艺术
💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 日期和时间在计算机编程…...
JOSEF约瑟 智能电流继电器KWJL-20/L KWLD26 零序孔径45mm 柜内导轨式安装
KWJL-20智能电流继电器 零序互感器: KWLD80 KWLD45 KWLD26 KWJL-20 一、产品概述 KWJL-20系列智能剩余电流继电器(以下简称继电器)适用于交流电压至660V或更高的TN、TT、和IT系统,频率为50Hz。通过零序电流互感器检测出超过…...
NLP技术如何为搜索引擎赋能
目录 1. NLP关键词提取与匹配在搜索引擎中的应用1. 关键词提取例子 2. 关键词匹配例子 Python实现 2. NLP语义搜索在搜索引擎中的应用1. 语义搜索的定义例子 2. 语义搜索的重要性例子 Python/PyTorch实现 3. NLP个性化搜索建议在搜索引擎中的应用1. 个性化搜索建议的定义例子 2…...
演唱会没买到票?VR直播为你弥补遗憾
听说周杰伦开了演唱会?没买到票的人是不是有着大大的遗憾呢?很多时候大型活动、演唱会都会因为场地限制而导致很多人未能有缘得见,而且加上票价成本高,“黄牛票”事件频出,我们的钱包受不住啊!!…...
myabtis的缓存级别
文章目录 MyBatis缓存的区别是什么作用范围方面有哪些差异生命周期数据进行了存储缓存的优缺点 MyBatis缓存的区别是什么 MyBatis 提供了一级缓存和二级缓存,这两者的主要区别在于其作用范围和生命周期。 一级缓存:一级缓存是 SqlSession 级别的缓存。…...
gin框架再探
Gin框架介绍及使用 | 李文周的博客 (liwenzhou.com) lesson03_gin框架初识_哔哩哔哩_bilibili 1.路由引擎 //路由引擎 rgin.Default() 2.一些http请求方法 get post put delete等等 遇到什么路径,执行什么函数 r.GET("/hello",func{做你想做的事返回…...
经典算法-----约瑟夫问题(C语言)
目录 前言 故事背景 约瑟夫问题 环形链表解决 数组解决 前言 今天我们来玩一个有意思的题目,也就是约瑟夫问题,这个问题出自于欧洲中世纪的一个故事,下面我们就去通过编程的方式来解决这个有趣的问题,一起来看看吧!…...
代码随想录 动态规划Ⅴ
494. 目标和 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - ,然后串联起所有整数,可以构造一个 表达式 : 例如,nums [2, 1] ,可以在 2 之前添加 ,在 1 之前添加 - …...
驱动DAY9
驱动文件 #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/fs.h> #include <linux/io.h> #include <linux/device.h> #incl…...
03贪心:摆动序列
03贪心:摆动序列 376. 摆动序列 局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。 整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。…...
javascript获取元素在浏览器中工作区域的左、右、上、下距离,或带滚动条的元素在页面中的大小
//获取元素在包含元素框中的大小 //第1个函数为获取元素在包含元素中左内边框的距离 function getELementLeft(element){//获取元素在包含元素左边距离var actualeftelement.offsetLeft;//获取元素的上级包含元素var currentelement.offsetParent;//循环到一直没有包含元素whil…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
