【C++程序员的自我修炼】初始化列表

一半烟火以谋生

一半诗意以谋爱


契子✨ 

我们之前已经讲过了构造函数的初始化:前期回顾-构造函数

但是难免会遇到连构造函数都不好解决的问题

比如:

错误示范

class A
{
public:
	A(int n)
	{
		this->_a = n;
		this->_b = n;
	}
private:
	const int _a;
	int _b;
};

因为 const 修饰的变量具有常性,也就是只能读不能写

所以 const 修饰的变量只能在定义的时候初始化,我们可以在声明的时候给缺省值来解决这个问题

const int _a = 10;

但是铁铁们知道这么做的本质是什么吗?

接下来我将带大家介绍:


初始化列表介绍

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个 成员变量 后面跟一个放在括号中的初始值或表达式
以下就是我们的要传参初始化列表: 
class A
{
public:
	A(int n)
		:_a(n)
		,_b(n)
	{
	}
private:
	int _a ;
	int _b;
};
当然我们也可以给 缺省值 进行无参的初始化定义
class A
{
public:
	A(int n = 4)
		:_a(n)
		,_b(n)
	{
	}
private:
	int _a ;
	int _b;
};
我们还可以在初始化列表中进行 malloc 的动态空间开辟操作
class A
{
public:
	A(int n = 4)
		:_a(n)
		, _b((int*)malloc(40))
	{
		memset(_b, 0, 40);
	}
private:
	int _a;
	int* _b;
};

注意:

初始化列表本质可以理解为每个对象中成员定义的地方
所有的成员可以在初始化列表初始化,也可以在函数体内初始化

比如:以上代码我在初始化列表中定义了 10 个 int 类型的空间,并在函数体内全部初始化为 0

我们这里规定一下:在构造函数进行初始化操作叫做在函数体内部进行初始化,在初始化列表初始化时叫做在对象定义的时候进行初始化

可能你会问:为什么要专门规定一个对象的成员变量初始化的地方呢?普通的变量不管是在函数体内部初始化还是在初始化列表初始化,都没有什么影响

但是有些特殊的成员变量,比如:

引用成员变量

const成员变量

没有默认构造函数的自定义类型成员变量

是不能在函数体内部初始化的

 

初始化列表的必用场景 

引用成员变量

错误示范

class A
{
public:
	A(int n = 4)
	{
		_a = n;
	}
private:
	int& _a ;
};

为什么呢?因为引用必须在定义的时候初始化:

定义一般变量时:

<1>声明:声明变量类型和名字 

<2>定义:根据类型分配内存地址空间 

<3>初始化:将初始值拷贝到变量的内存地址空间中

定义引用类型时:

将引用绑定到初始化对象

因此定义引用类型时必须有初始值对象,也就是必须在定义的时候初始化

正确写法

class A
{
public:
	A(int n = 4)
		:_a(n)
	{
	}
private:
	int& _a;
};

因为初始化列表本质可以理解为每个对象中成员定义的地方,所以用初始化列表写

const 成员变量

因为 const 修饰的变量具有常性,所以必须在定义的时候初始化:

class A
{
public:
	A(int n = 4)
		:_a(n)
	{
	}
private:
	const int _a;
};

自定义类型成员(且该类没有默认构造函数)

错误示范

class A
{
public:
	A(int a,int b,int c)
	{
		this->_a = a;
		this->_b = b;
		this->_c = c;
	}
private:
	int _a;
	int _b;
	int _c;
};

class B
{
public:
	B(int n = 4)
	{
		_cc = n;
        _aa(0, 0, 0);
		_bb(1, 1, 1);
	}
private:
	A _aa;
	A _bb;
	int _cc;
};

在构造函数的章节我们提过:

  • 自动生成的构造会处理自定义类型,它会去调用自定义类型的默认构造

所以自定义类型会先调自己的默认拷贝构造,而这里我们恰恰没写呢?这就是报错的原因

没事~交给我们的初始化列表即可

正确写法

class A
{
public:
	A(int a, int b, int c)
	{
		this->_a = a;
		this->_b = b;
		this->_c = c;
	}
private:
	int _a;
	int _b;
	int _c;
};

class B
{
public:
	B(int n = 4)
		:_aa(0, 0, 0)
		,_bb(1, 1, 1)
	{
		_cc = n;
	}
private:
	A _aa;
	A _bb;
	int _cc;
};

这样我们就成功初始化了呢~

初始化的一些小细节

class Date
{
public:
Date(int year, int month, int day)
 {
     _year = year;
     _month = month;
     _day = day;
 }
private:
int _year;
int _month;
int _day;
};

我们来看一下,之前写的日期类 Date :

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值


简单来说:若是没有用初始化列表,在函数内的 初始化 语句并不是真正的初始化,而是相当于初赋值,只有最后的赋值等式才会初始化生效

	Date(int year, int month, int day)
	{
		_year = year;
		_year = 10;
		_month = month;
		_month = 20;
		_day = day;
		_day = 30;
	}

比如说以上代码:最后初始化成功的就是:_year = 10,_month = 20,_day = 30

如果用我们的初始化列表的话

	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{
	}

以上是正确的写法,但是不能初始化两次

错误示范

	Date(int year, int month, int day)
		:_year(year)
		, _year(10)
		,_month(month)
		,_day(day)
	{
	}

但是初始化后,仍可以赋初值

	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{
		this->_year = 10;
	}

总结

每个成员变量在初始化列表中初始化只能初始化一次
类中包含以下成员,必须放在初始化列表位置进行初始化:
<1>引用成员变量
<2>const成员变量
<3>自定义类型成员(且该类没有默认构造函数时)

 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,

一定会先使用初始化列表初始化

注意:初始化列表在对象定义时,自动调用初始化列表,即使不写系统也会默认生成

如果我们不显式写出初始化列表,编译器会自动生成,对于内置类型,我们会对他进行初始化,对于自定义类型,会去调用它的默认构造函数

 这里跟构造函数一样~

内置类型传缺省值和初始化列表联系

回顾一下我们构造函数里讲过的给内置类型传缺省值

这里传的缺省值是给谁用的呢?

此时的你心里估计已有了明确的答案 -- 初始化列表

#include<iostream>
#include<assert.h>
#include<cstdlib>
using std::cout;
using std::endl;

class A
{
public:
	A()
		: _b(5)
	{
	}
	void Print();
private:
	int _a = 10;
	int _b = 20;
};

void A::Print()
{
	cout << _a <<" "<<_b << endl;
}

int main()
{
	A aa;
	aa.Print();
	system("pause");
	return 0;
}

看看以上的程序的结果是什么呢?


首先我们赋予了内置类型缺省值,编译器会将缺省值给初始化列表

由 初始化列表 初始化,也就是 ~  10 20

但是我们的初始化列表已将 _b 初始化为 5,说明不接受 _b 的缺省值

所以正确的结果是:10 5


成员变量的顺序

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后

次序无关
#include<iostream>
#include<cstdlib>
using std::cout;
using std::endl;

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();
	system("pause");
	return 0;
}

 看看以上的代码分析程序:

A、输出1  1
B、程序崩溃
C、编译不通过
D、输出1  随机值

我们可以看到程序运行的结果为 D:
<1>根据成员变量声明的顺序,理应先初始化 _a2 但是 _a1 还没有初始化所以是随机值

<2>接下来到 _a1 初始化,就是传参初始化,所以是 1


先介绍到这里啦~

有不对的地方请指出💞

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS-43-Node.js02-安装Node.js和npm

Node.js是一个基于Chrome V8引擎的JavaScript运行时环境&#xff0c;可以让JavaScript实现后端开发&#xff0c;所以&#xff0c;首先在本机安装Node.js环境。 一、安装Node.js 官网&#xff1a;下载 Node.js 默认两个版本的下载&#xff1a; 64位windows系统的LTS(Long Tim…

记录一下我102连不上MySQL的问题 NotBefore

【背景描述】我在102上是能登录上MySQL的&#xff0c;但是用客户端&#xff08;DataGrip、SQLyog就连不上&#xff09; 【解决方案】 加个这个?useSSLfalse&serverTimezoneUTC 【另外的小问题】如果直接输mysql 上面这个不是报错&#xff0c;不用管 再输mysql -uroot -p…

Ubuntu系统安装APITable多维表格平台结合内网穿透实现公网访问

文章目录 前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c;是一款面向 API 的智能多维表格。它将复杂的可视化数据库、电子表格、实时在线协同、低代码开发技术四合为一&am…

mybatis-puls 条件分析插件

一&#xff0c;能做什么 我们在平时的开发中,会遇到一些慢sql. MP也提供了性能分析插件,如果超过这个时间就停止运行! 二&#xff0c;如何实现 2.1引入条件分析插件 //性能分析BeanProfile({"dev","test"}) //设置dev 和 test环境开启public Performanc…

【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题

文章目录 一、什么是时间复杂度和空间复杂度&#xff1f;1.1 算法效率1.2 时间复杂度的概念1.3 空间复杂度的概念1.4 复杂度计算在算法中的意义 二、时间复杂度的计算2.1 大O渐进表示法2.2 常见时间复杂度计算举例 三、空间复杂度的计算四、Leetcode刷题1. 消失的数2. 旋转数组…

探索设计模式的魅力:融合AI大模型与函数式编程、开启智能编程新纪元

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索AI大模型与函数式编程模式融合之旅✨ 在编程世界的广阔疆域里&#xff0c;两大…

组织机构代码是哪几位?营业执照怎么看组织机构代码?

组织机构代码是哪几位? 组织机构代码通常指的是组织机构代码证上的一组特定数字&#xff0c;它用于唯一标识一个组织或机构。在中国&#xff0c;组织机构代码由9位数字组成&#xff0c;前8位是本体代码&#xff0c;最后1位是校验码。这组代码是按照国家有关标准编制的&#x…

第一部分-基础入门-学习导航

专题地址:MacOS一站式程序开发系列专题 第一部分:基础入门学习导航 OSX-01-Mac OS应用开发概述:简单介绍下MacOS生态、Xcode使用以及使用Xcode创建app的方法OSX-02-Mac OS应用开发系列课程大纲和章节内容设计:介绍下此系列专题的文章内容组织形式以及此系列专题的覆盖内容…

帮助中心最核心的内容,你都知道吗?

帮助中心&#xff0c;其实就是个解决问题的“百事通”。当你在使用某产品时&#xff0c;遇到了一些问题&#xff0c;就可以到帮助中心去查询相关的信息以解决问题。很多公司都会搭建帮助中心&#xff0c;那么&#xff0c;帮助中心的核心内容都有哪些呢&#xff1f;这就是今天我…

K8s拉取habor镜像

目录 在daemon.json中添加仓库地址 重新加载daemon.json并重启docker 在目标node节点添加域名 验证目标node是否能正常登录镜像仓库 创建pod资源 加载yml文件 验证 查看pod的ip与端口号 在daemon.json中添加仓库地址 此处需要在创建资源对象所在的节点进行添加 路径&a…

c++的学习之路:24、 二叉搜索树概念

摘要 本章主要是讲一下二叉搜索树的实现 目录 摘要 一、二叉搜索树概念 二、 二叉搜索树操作 1、二叉搜索树的查找 2、二叉搜索树的插入 3、二叉搜索树的删除 三、二叉搜索树的实现 1、插入 2、中序遍历 3、删除 4、查找 四、二叉搜索树的递归实现 1、插入 2、删…

Web前端-Vue组件库Element

黑马程序员JavaWeb开发教程 文章目录 一、快速入门&#xff08;1&#xff09;什么是Element&#xff08;2&#xff09;快速入门 二、常见组件1、表格2、分页&#xff08;Pagination&#xff09;3、表单 三、案例&#xff08;1&#xff09;根据页面原型完成员工管理页面开发&…

vue实现文字转语音的组件,class类封装,实现项目介绍文字播放,不需安装任何包和插件(2024-04-17)

1、项目界面截图 2、封装class类方法&#xff08;实例化调用&#xff09; // 语音播报的函数 export default class SpeakVoice {constructor(vm, config) {let that thisthat._vm vmthat.config {text: 春江潮水连海平&#xff0c;海上明月共潮生。滟滟随波千万里&#xf…

MySQL高级(性能分析-查看执行频次、慢查询日志)

目录 1、SQL性能分析 1.1、SQL执行频率 1.2、慢查询日志 1、SQL性能分析 1.1、SQL执行频率 MySQL 客户端连接成功后&#xff0c;通过 show [ session | global ] status 命令可以提供服务器状态信息。通过如下指令&#xff0c;可以查看当前数据库的 insert、update、delete、…

[CSS]样式属性+元素设置

哎呀&#xff0c;好多东西&#xff0c;根本记不住&#xff0c;更多的还是边用边记吧&#xff0c;这里的代码就当使用范例&#xff0c;但其实如果可以让gpt应该会更好&#xff0c;哎学吧&#xff0c;反正记得住当然更好 文本 属性名描述word-break单词换行。取值如下&#xff1…

海康威视IPC配置NAS

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装Samba1.Windows102.Ubuntu-22.04 二、配置IPC总结 前言 简而言之&#xff0c;我手上几个海康威视的IPC都是比较老的设备吧&#xff0c;经过测试不支持…

【C语言】贪吃蛇项目(1) - 部分Win32 API详解 及 贪吃蛇项目思路

文章目录 一、贪吃蛇项目需要实现的基本功能二、Win32 API介绍2.1 控制台2.2 部分控制台命令及调用函数mode 和 title 命令COORD 命令GetStdHandle&#xff08;获取数据&#xff09;GetConsoleCursorInfo&#xff08;获取光标数据&#xff09;SetConsoleCursorInfo &#xff08…

Free day2

1.总结串口的发送和接收功能使用到的函数 发送函数&#xff1a;HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout) 参数1&#xff1a;指定要使用的串口 参数2&#xff1a;要发送的数据字节数&#xff…

VIT论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2010.11929.pdf VIT论文阅读 摘要INTRODUCTION结论RELATEDWORKMETHOD1.VISIONTRANSFORMER(VIT)整体流程消融实验HEAD TYPE AND CLASSTOKENpoisitional embedding 整体过程公式Inductive biasHybrid Architecture 2.FINE-TUNINGANDH…

阿里面试:DDD中的实体、值对象有什么区别?

在领域驱动设计&#xff08;DDD&#xff09;中&#xff0c;有两个基础概念&#xff1a;实体&#xff08;Entity&#xff09;和值对象&#xff08;Value Object&#xff09;。 使用这些概念&#xff0c;我们可以把复杂的业务需求映射成简单、明确的数据模型。正确使用实体和值对…