C++ 初始化列表详解

news2024/11/18 16:42:56

目录

1.什么是初始化列表

2.什么时候需要使用初始化列表?

3.初始化列表的效率

4.初始化列表的初始化顺序


1.什么是初始化列表

class A {
public:
	A(int value):m_dada(value)
	{

	}
	
private:
	int m_dada;
};

如上图,红色圈起来的部分,就是构造函数的初始化列表,以冒号开始,冒号后面依次列出需要赋值的成员变量和值。

2.什么时候需要使用初始化列表?

(1)当有成员变量是引用类型时

(2)当有数据成员是常量时

(3)当父类的构造函数有参数时

(4)当成员变量所属类型的构造函数有参数时

2.1当有成员变量是引用类型时

可以看到类中有一个引用类型的变量m_data,直接编译会报错,提示“必须初始化引用”,即使在构造函数里面赋值也不行,此时必须使用初始化列表,下面看看使用初始化列表后的情况。

可以看到,使用初始化列表后,编译成功。

2.2当有数据成员是常量时

可以看到,类中有个const常量m_data,直接编译会报错,提示“必须初始化常量”。下面看看使用初始化列表后的情况。

可以看到,使用初始化列表后,编译成功。

2.3当父类的构造函数有参数时

可以看到,B类的父类是A,A的构造函数有一个参数,在实现B类的构造函数时,如果不处理A类的构造函数,就会编译报错,提示“A类没有合适的默认构造函数可用”。下面看下使用了初始化列表后的情况。

可以看到,使用初始化列表后,编译成功。

2.4当成员变量所属类型的构造函数有参数时

可以看到,B类有一个数据成员A m_a,在B类的构造函数中没有对这个m_a作处理,导致编译报错,提示“A没有合适的默认构造函数可以”。下面看看使用了初始化列表后的情况。

3.初始化列表的效率


#include "stdafx.h"


#include <iostream>
using namespace std;

class A {
public:
	A()
	{
		cout << "call A()" << endl;
	}

	~A()
	{
		cout << "call ~A()" << endl;
	}
	
};

class B
{
public:
	B(A value) : m_a(value)
	{
		cout << "call B()" << endl;
		//m_a = value;
	}

	~B()
	{
		cout << "call ~B()" << endl;
	}

private:
	A m_a;
};

int main()
{
	A objA;
	B objB(objA);
    return 0;
}

上面这段代码,在B类的构造函数中,使用了初始化列表给成员变量A m_a进行赋值,运行结果如下:

可以看到在调用B类的构造函数时,调用了一次A类的析构函数,没有调用A类的构造函数,我想这是VS编译器的特殊设计造成的,换成其它编译器可能就不是这样了,这里我认为使用了初始化列表之后,应该在B类的构造函数中不会调用A类的构造函数和析构函数了,这样才符合使用初始化列表的效率更高的特点。

下面看一下没有使用初始化列表,而直接在B类构造函数中给m_a赋值的情况。

#include "stdafx.h"
#include <iostream>
using namespace std;

class A {
public:
	A()
	{
		cout << "call A()" << endl;
	}

	~A()
	{
		cout << "call ~A()" << endl;
	}
	
};

class B
{
public:
	B(A value) 
	{
		cout << "call B()" << endl;
		m_a = value;
	}

	~B()
	{
		cout << "call ~B()" << endl;
	}

private:
	A m_a;
};

int main()
{
	A objA;
	B objB(objA);
    return 0;
}

可以看到,如果直接在B类的构造函数中赋值,将会导致多一次A类构造函数的调用。

综上所述,使用初始化列表给成员变量设定初始值效率会更高,建议优先使用这种方法。对于基础类型的变量,比如int,bool类型,则没有必要非要采用初始化列表。

4.初始化列表的初始化顺序

编译器会将初始化列表一一转换成代码,并且这些代码会被放在用户编写的代码之前。初始化列表的初始化顺序是由数据成员的声明次序决定的,不是由初始化列表的排列次序决定的。

“初始化次序”和“初始化列表中的排列次序”如果不一致,将可能导致意想不到的风险。比如:

class C
{
private:
	int i;
	int j;
public:
	C(int value):j(value),i(j)
	{
		cout << "i = " << i << endl;
		cout << "j = " << j << endl;
	}
};

int main()
{
	C objC(10);
    return 0;
}

上述程序代码看起来像是要把j设初值为 value,再把i设初值为 j.问题在于,由于声明次序的缘故,初始化列表中的”i(j)”其实比”j(value)”更早执行。但因为j 一开始未有初值,所以i(j)的执行结果导致无法预知其值。

那么如何避免上面的问题呢,建议是如果要用一个成员变量的值给另外一个成员变量赋值,则建议将赋值的代码写在构造函数中,如下:

class C
{
private:
	int i;
	int j;
public:
	C(int value):j(value)
	{
		i = j;
		cout << "i = " << i << endl;
		cout << "j = " << j << endl;
	}
};

int main()
{
	C objC(10);
    return 0;
}

因为初始化列表的执行是在构造函数的用户代码之前,所以j会先被赋值。

接下来看看下面这段代码有没有什么问题。

class C
{
private:
	int i;
	int j;
public:
	C(int value):j(value)
	{
		i = j;
		cout << "i = " << i << endl;
		cout << "j = " << j << endl;
	}
};


class D : public C
{
private:
	int data;
public:
	int GetValue()
	{
		return data;
	}

	D(int value):data(value),C(GetValue())
	{
		cout << "data = " << data << endl;
	}
};

int main()
{
	D objD(10);
    return 0;
}

上面的代码中,在D类的构造函数使用了初始化列表,在初始化列表中调用了成员函数来给父类的构造函数传参,乍一看好像没什么问题,但是从最后的运行结果来看,i和j未被成功赋值,这是为什么呢?

这是因为在初始化列表中,父类的构造函数被优先执行,导致data还没来得及赋值。所以建议将父类的构造函数放在初始化列表的最前面,以避免上述问题。

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

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

相关文章

MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《5》

在上一篇文章的介绍中&#xff0c;我们知道语义分割可以对图像中的每个像素进行类别预测。这节主要讲关于全卷积网络(Fully Convolutional Network,FCN)&#xff0c;实现从图像像素到像素类别的变换。 那这里的卷积神经网络跟以往的有什么不一样的地方吗? 这里的网络是通过转置…

Java中享元模式是什么/享元模式有什么用,编程如何实现,哪里用到了享元模式

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 5.8 享元模式 5.8.1 概述 运用共享技术来有效地支持大量细粒度对象的复用&#xff0c;通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象…

图文并茂strapi 4.5.5自定义搭建指南以及数据库字段名接口返回mapping分析

strapi是什么&#xff1f; 基于Nodejs的开源免费CMS框架 为什么选择它&#xff1f; 基于nodejs,100&#xff05;JavaScript&#xff0c;上手迅速可轻松创建功能强大且可自定义的API可以使用任何喜欢的数据库 先决条件 首先你的电脑需要具备以下环境&#xff0c;再执行命令…

技术破局:程序员2023为何跳出舒适圈?

1前言今天的冬日暖阳高照&#xff0c;给我羽绒服下的肉身火一般的燥热&#xff0c;给了我一个错觉&#xff0c;以为到了阳春三月。刚刚送完老妈还有老婆孩子回老家&#xff0c;我坐到电脑机器前&#xff0c;准备捋一下思绪&#xff0c;回首2022的生活和工作。 2 2022 回顾今年用…

Linux下C/C++实现cpustat(测量CPU利用率)

在Linux中&#xff0c;cpustat定期转储正在运行的进程的当前CPU利用率统计信息。cpustat已被优化为具有最小的CPU开销&#xff0c;与top相比&#xff0c;通常使用约35%的CPU。cpustat还包括一些简单的统计分析选项&#xff0c;可以帮助描述CPU的加载方式。 cpustat介绍 cpust…

大数据概论

大数据概论大数据概论概念特点(4V)Volume(大量)Velocity(高速)Variety(多样)Value(低价值密度)应用场景发展前景部门间业务流程分析部门组织结构大数据概论 概念 大数据(BigData)&#xff0c;指无法在一定时间范围内\textcolor{Red}{无法在一定时间范围内}无法在一定时间范围…

iOS—Effective Objective—C2.0(2)

文章目录对象&#xff0c;消息&#xff0c;运行期理解“属性”概念合成与存取dynamic关键字属性特性原子性读/写权限内存管理语义方法名为什么几乎所有的属性都可以使用nonatomic&#xff1a;要点在对象的内部尽量直接访问实例变量惰性初始化&#xff1a;要点理解“对象同等性”…

2022年度总结——平凡之路

文章目录一、缘起二、回首2022三、展望2023四、结束语我是平凡的人&#xff0c;总要接受普通平凡的自己。一、缘起 我注册CSDN的时间是2021-07-25&#xff0c;这是一个值得纪念的时间。不过那时候的我并没有写博客&#xff0c;只是在CSDN游览一些文章&#xff0c;查看资料&…

一文读懂Java垃圾回收机制及算法原理万字详解

Java垃圾回收机制及算法 文章目录Java垃圾回收机制及算法垃圾回收概述垃圾回收-对象是否已死判断对象是否存活 - 引用计数算法判断对象是否存活-可达性分析算法可达性分析算法JVM之判断对象是否存活再谈引用垃圾收集算法分代收集理论标记-清除算法什么是标记-清除算法?标记-复…

读书:《卡片笔记写作法》

2023年罗胖跨年演讲时提到了一个故事&#xff0c;说Flomo的创始人有3个原则&#xff1a;一不在软件内弹广告&#xff0c;二不做永久会员&#xff0c;三不融资。我就马上试用了一下这款Flomo软件&#xff0c;然后就发现了《卡片笔记写作法》这本书。 这本书的卡片写作法来自于一…

【Qt】QtCreator新建Application项目的6类应用程序的示例

【Qt】QtCreator新建Application项目的6类应用程序的示例1、背景2、Application分类1、背景 操作系统&#xff1a;windows10专业版。 Qt版本&#xff1a;qt-opensource-windows-x86-msvc2013_64-5.7.1.exe 注意&#xff1a;安装了该exe可执行文件&#xff0c;就自动安装了qtcr…

(考研湖科大教书匠计算机网络)第一章概述-第一节:因特网概述

文章目录一&#xff1a;网络、互联网和因特网基本概念二&#xff1a;因特网发展的三个阶段三&#xff1a;ISP和基于ISP的三层结构的因特网&#xff08;1&#xff09;ISP&#xff08;2&#xff09;基于ISP的三层结构的因特网四&#xff1a;因特网的标准化工作五&#xff1a;因特…

KMP算法--子串查找问题

目录 一.前言 二.KMP算法简介 三.关键概念1&#xff1a;字符串的前后缀 四. 关键概念2&#xff1a;字符串相等前后缀与最长相等前后缀长度 五.关键概念3&#xff1a;Next数组 六.Next数组在算法中的应用&#xff1a; 七.模式串Next数组的构建 先膜拜一下三位神仙&#x…

面试前端数组去重,我会问这3个小问题

关于数组去重&#xff0c;已经是一个老生常谈的问题了&#xff0c;网络上已经有N篇关于数组去重的讲解了&#xff0c;所以&#xff0c;凡是能看见这篇博客的&#xff0c;我们都是有缘人&#xff0c;希望2023年你可以乘风破浪&#xff0c;职击沧海。而一般面试的时候&#xff0c…

MySQL调优-高性能业务表结构设计

目录 前言记录&#xff1a; 数据库表设计 范式设计 什么是范式&#xff1f; 数据库设计的第一范式 数据库设计的第二范式 数据库设计的第三范式 范式说明 反范式设计 什么叫反范式化设计&#xff1f; 反范式设计-商品信息 范式化和反范式总结 实际工作中的反范式实…

C++ stack和queue

1. stack的介绍和使用1.1 stack的介绍1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容器&…

基于深度学习的自然语言处理

1、什么是自然语言处理&#xff1f; 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门融语言学、计算机科学、…

【信号与系统】预习笔记(每日更新ing)

2023.1.8已打卡 信号与系统&#xff08;一&#xff09;信号与系统概述1.0 常见三角公式1.1 信号与系统1.2 信号的表述、分类1.3 信号的运算&#xff08;二&#xff09;连续系统的时域分析&#xff08;三&#xff09;离散系统的时域分析&#xff08;四&#xff09;傅里叶变换与频…

软件质量保证与软件测试复习文档

目录 引言&#xff1a; 内容&#xff1a; 一、Ron patton《软件测试》中谈到的软件缺陷的定义被业界广泛认可&#xff0c;主要包括哪五条&#xff1f; 二、软件测试人员的主要工作职责是什么&#xff0c;一般围绕哪几个重要文档开展工作&#xff1f; 三、什么是软件测试模…

差分算法介绍

一、基本概念 差分算法是前缀和算法的逆运算&#xff0c;可以快速的对数组的某一区间进行计算操作。 例如&#xff0c;有一数列 a[1],a[2],.…a[n]&#xff0c;且令 b[i] a[i]-a[i-1],b[1]a[1]&#xff0c;那么就有 a[i] b[1]b[2].…b[i] a[1]a[2]-a[1]a[3]-a[2].…a[i]-a[i…