当前位置: 首页 > news >正文

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们&#xff0c;大家好。这里是C入门的第十一讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 初始化列表 1.1 引入 1.2 初始化列表 1.3 初始化列表的注意事项 1.…...

OpenAI开发系列(二):大语言模型发展史及Transformer架构详解

全文共1.8w余字&#xff0c;预计阅读时间约60分钟 | 满满干货&#xff0c;建议收藏&#xff01; 一、介绍 在2020年秋季&#xff0c;GPT-3因其在社交媒体上病毒式的传播而引发了广泛关注。这款拥有超过1.75亿参数和每秒运行成本达到100万美元的大型语言模型&#xff08;Large …...

Gson - 一个Java序列化/反序列化库

官网 GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back 项目简介 一个Java序列化/反序列化库&#xff0c;用于将Java对象转换为JSON和返回JSON。 Gson is a Java library that can be used to convert Java…...

6-1 汉诺塔

汉诺&#xff08;Hanoi&#xff09;塔问题是一个经典的递归问题。 设有A、B、C三个塔座&#xff1b;开始时&#xff0c;在塔座A上有若干个圆盘&#xff0c;这些圆盘自下而上&#xff0c;由大到小地叠在一起。要求将塔座A上的圆盘移到塔座B上&#xff0c;并仍按同样顺序叠放。在…...

Linux之initd管理系统(海思、ZYNQ、复旦微)添加密码登录验证

设置root用户密码&#xff1a;passwd命令设置密码&#xff0c;即修改/etc/passwd文件 一、串口提示输入用户名密码方法 修改 /etc/inittab 方法一&#xff1a; 增加&#xff1a; ::askfirst:-/bin/login 注释&#xff1a; #::respawn:/sbin/getty -L ttyS000 115200 vt…...

怎么更改代理ip,代理ip如何切换使用?

我们要如何使用HTTP代理&#xff0c;对它进行切换使用呢&#xff1f; 如果你购买了青果网络的HTTP代理&#xff0c;可以在文档这边获取使用方法&#xff1a; 可以在这里调试&#xff1a; 也可以在这里选择key提取。 如果有的朋友们想利用利用python&#xff0c;每隔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&#xff1a;屏幕高度 window.innerHeight&#xff1a;视口高度&#xff08;去除浏览器头尾的高度&#xff09; document.body.clientHeight&#xff1a;内容高度 vh&#xff1a;网页视口高度的1/100 vw&#xff1a;网页视口宽度的1/100 vmax&#xff…...

uni-app 之 解决u-button始终居中问题

uView中u-button始终居中问题如何解决的简单方法&#xff1f; 1&#xff1a;给该元素margin-right: 0;可以达到向右靠齐&#xff1b; 2&#xff1a;给该元素的父元素设置float: right image.png <u-button style"width: 50px; margin-left: 0;" plain"t…...

Python日期处理库:掌握时间的艺术

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 日期和时间在计算机编程…...

JOSEF约瑟 智能电流继电器KWJL-20/L KWLD26 零序孔径45mm 柜内导轨式安装

KWJL-20智能电流继电器 零序互感器&#xff1a; KWLD80 KWLD45 KWLD26 KWJL-20 一、产品概述 KWJL-20系列智能剩余电流继电器&#xff08;以下简称继电器&#xff09;适用于交流电压至660V或更高的TN、TT、和IT系统&#xff0c;频率为50Hz。通过零序电流互感器检测出超过…...

NLP技术如何为搜索引擎赋能

目录 1. NLP关键词提取与匹配在搜索引擎中的应用1. 关键词提取例子 2. 关键词匹配例子 Python实现 2. NLP语义搜索在搜索引擎中的应用1. 语义搜索的定义例子 2. 语义搜索的重要性例子 Python/PyTorch实现 3. NLP个性化搜索建议在搜索引擎中的应用1. 个性化搜索建议的定义例子 2…...

演唱会没买到票?VR直播为你弥补遗憾

听说周杰伦开了演唱会&#xff1f;没买到票的人是不是有着大大的遗憾呢&#xff1f;很多时候大型活动、演唱会都会因为场地限制而导致很多人未能有缘得见&#xff0c;而且加上票价成本高&#xff0c;“黄牛票”事件频出&#xff0c;我们的钱包受不住啊&#xff01;&#xff01;…...

myabtis的缓存级别

文章目录 MyBatis缓存的区别是什么作用范围方面有哪些差异生命周期数据进行了存储缓存的优缺点 MyBatis缓存的区别是什么 MyBatis 提供了一级缓存和二级缓存&#xff0c;这两者的主要区别在于其作用范围和生命周期。 一级缓存&#xff1a;一级缓存是 SqlSession 级别的缓存。…...

gin框架再探

Gin框架介绍及使用 | 李文周的博客 (liwenzhou.com) lesson03_gin框架初识_哔哩哔哩_bilibili 1.路由引擎 //路由引擎 rgin.Default() 2.一些http请求方法 get post put delete等等 遇到什么路径&#xff0c;执行什么函数 r.GET("/hello",func{做你想做的事返回…...

经典算法-----约瑟夫问题(C语言)

目录 前言 故事背景 约瑟夫问题 环形链表解决 数组解决 前言 今天我们来玩一个有意思的题目&#xff0c;也就是约瑟夫问题&#xff0c;这个问题出自于欧洲中世纪的一个故事&#xff0c;下面我们就去通过编程的方式来解决这个有趣的问题&#xff0c;一起来看看吧&#xff01…...

代码随想录 动态规划Ⅴ

494. 目标和 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 &#xff0c;在 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贪心&#xff1a;摆动序列 376. 摆动序列 局部最优&#xff1a;删除单调坡度上的节点&#xff08;不包括单调坡度两端的节点&#xff09;&#xff0c;那么这个坡度就可以有两个局部峰值。 整体最优&#xff1a;整个序列有最多的局部峰值&#xff0c;从而达到最长摆动序列。…...

javascript获取元素在浏览器中工作区域的左、右、上、下距离,或带滚动条的元素在页面中的大小

//获取元素在包含元素框中的大小 //第1个函数为获取元素在包含元素中左内边框的距离 function getELementLeft(element){//获取元素在包含元素左边距离var actualeftelement.offsetLeft;//获取元素的上级包含元素var currentelement.offsetParent;//循环到一直没有包含元素whil…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...