C++ 初始化列表详解

article/2025/9/10 21:18:37

目录

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还没来得及赋值。所以建议将父类的构造函数放在初始化列表的最前面,这样可以提醒自己要先检查GetValue是否能正确返回数据。另外如果要避免上述问题,可以把C(GetValue())改成C(value),注意千万不要直接把C(GetValue())挪到D类的构造函数内部,会编译失败


http://chatgpt.dhexx.cn/article/9ggxJZ86.shtml

相关文章

【C++】-- 初始化列表

目录 一、用初始化列表初始化对象 1.初始化列表用法 2.初始化列表特性 二、explicit关键字 1.内置类型的隐式转换 2.如何避免单参构造函数初始化发生隐式类型转换 三、匿名对象 1.匿名对象定义 2.匿名对象应用场景 创建一个类对象时&#xff0c;编译器通过调用构造函…

字符串逆序(数组倒序输出)

题目信息&#xff1a; 样例输出 copy edcba 新手导读&#xff1a; 题目描述信息&#xff1a;字符串的倒序输出肯定是字符数组的倒序输出&#xff1b; 输入信息&#xff1a;输入条件是最后字符不为回车&#xff1b;所以应该先用变量存入字符进行判断&#xff0c;再使用这个…

C语言实现字符串倒序

C语言显示字符串倒序 倒序字符串的方法很多&#xff0c;这里给出常见的两种 1.倒序字符串指针法 void reverse_string(char *arr) {int len strlen(arr);char* left arr; //指向头部的指针char* right arr (len - 1); //指向尾部的指针char temp;while(left <…

C语言:输入一串字符串,并倒序输出(vs)

一&#xff1a;问题&#xff1a; 输入一串字符串倒序输出 例&#xff1a;输入abcdefg 输出gfedcba 二&#xff1a;思路&#xff1a; &#xff08;1&#xff09;先输入一串字符串&#xff0c;然后利用for语句倒序输出即可&#xff1b; 三&#xff1a;实现过程&#xff1a; …

字符串倒序输出

题目&#xff1a;输入一个字符串&#xff0c;将该串倒序输出。例如输入字符串hello&#xff0c;倒序输出为olleh。 str1 str(input(请输入字串: )) print(输入的字符是&#xff1a;%s%str1) str2 #定义一个空串用来接收倒序后的字串 for i in str1[::-1]:#对字串进行倒序输出…

字符串的倒叙输出(直接倒叙和单词倒叙)

一.字符串的直接倒叙 输入一个字符串&#xff0c;实现倒叙输出,我想到的方法有两种&#xff1a; 首先把输入的字符串存入一个数组&#xff1b; 1.方法一&#xff1a;直接逆序打印这个数组&#xff0c;即从最后一个元素向前打印&#xff1b; C代码&#xff1a; #include <std…

字符串倒序输出的五种方法

1. 使用数组循环 public static String array(String s){ int lengths.length(); char[] arrays.toCharArray(); for(int i0;i<length/2;i){ array[i]s.charAt(length-1-i); array[length-1-i]s.charAt(i); } return new String(array); } 2. StringBuffer的reverse方法 pu…

idea中git更新代码到本地之后自己写的代码不见了

今天在合并分支的时候不小心选错了合并选项&#xff0c;导致本地刚写的代码都没了 解决办法 1.找到本地历史记录 2.选择自己想要的版本 3.点击RevertSelection恢复

Git篇:使用Git将代码库更新到本地(完整版)

环境&#xff1a;Git已安装&#xff08;皮一下&#xff09; 新建一文件夹 右键&#xff0c;Git Bash Here git init 添加库 git remote add origin 想要更新的源码地址 将库里的代码下载到本地 git pull origin master 到此为止&#xff0c;第一次下载项目流程就结束了&am…

git 查看远程分支更新到本地,本地代码暂存,取出

一 、远程分支更新到本地 1.将一个项目更新到本地 git clone 项目地址 2.进入项目文件夹下 git branch 会显示 3. 在远端新建分支。 新建一个dev分支。大家合并的分支。再给每一个开发者建一个分支。比如我的jhj分支 4 .获取远端的分支&#xff0c;新建成功后在输入下边…

从远程仓库git更新(update)代码,显示更新成功,但是本地代码并没有改变

没有拉取更新成功的原因是本地有修改内容&#xff0c;解决方法如下&#xff1a; 1、在要更新的代码文件所在的文件夹&#xff08;含.git文件&#xff09;中打开gitBash&#xff0c;然后采用以下代码隐藏本地修改。 git stash结果如图&#xff1a; 2、选择IDEA中Git里面的upd…

git更新代码到本地后发现自己的代码不见了

解决办法&#xff1a; 利用webstorm的git插件恢复代码 然后选择你需要恢复的文件点击恢复按钮即可 可以双击文件查看要恢复的文件和本地文件的区别

GitHub上传本地代码/更新本地代码

上传本地代码 第一步&#xff1a;去github上创建自己的Repository&#xff0c;创建页面如下图所示&#xff1a; 红框为新建的仓库的https地址 第二步&#xff1a; echo “# aaa” >> README.md 注意&#xff1a;aaa是新创建的仓库名 第三步&#xff1a;建立git仓…

Git拉取上传更新代码

目录 一、将git上的项目拉取到本地 二、git提交更新代码 一、git上的项目拉取到本地 1.在本地创建一个文件夹 2.在本地文件夹中右键选择git bash here 3.在终端中输入克隆远程库的命令:git clone git上的项目地址 二、git提交更新代码 1.同步远程代码git pull origin mast…

使用Git将代码传送(更新或者下载到本地)到github/gitee

一.上传到Github 1.首先要下载git&#xff0c;正常下载就行了 2.下载git后&#xff0c;在终端输入git init&#xff1a; 如下&#xff1a;我需要将 这个文件夹中的程序上传到github。 那么就在这里输入git init 3.之后再输入git add . 4. 然后在输入git status&#xff0c;…

0801-2execjs安装

删除线格式 这个老哥的教程太靠谱了&#xff0c;我给他点了个赞 重装VNPY 之前安装的不知道为什么没有vnpy文件夹 感谢百度 要不然我重新安不上了 进入盘符 /d 感谢

execjs执行包含中文参数的JavaScript

抓取到了一段包含数据的JavaScript代码&#xff1a; import re import requestsheaders {"user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36","accept": &quo…

python运行execjs中出现编码问题

在破解豆瓣的window.__DATA__时&#xff0c;使用python的execjs执行js&#xff0c;会有这个错误&#xff1a; Exception in thread Thread-1: Traceback (most recent call last):File "E:\codes\python\lib\threading.py", line 917, in _bootstrap_innerself.run()…

解决execjs gbk编码错误

解决execjs subprocess中报错&#xff0c;UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xaf in position 1527: illegal multibyte sequence 问题描述 如果使用execjs执行含有中文的js文件&#xff0c;将会报错gbk无法解码文件的问题 报错如图所示&#xff1a; 解…

Python 使用execjs调用网页js 进行数据加密

最近做一个数据采集项目的时候需要自动采集网站的招投标数据 &#xff0c;随便打开一个网站 打开开发者模式&#xff0c;输入关键词&#xff0c;点击搜索&#xff0c;获得以下内容 可以看到请求链接和请求类型&#xff0c;请求类型Content-Type:是application/x-www-form-urle…