普通构造函数VS初始化列表构造函数

初始化列表构造函数最优先匹配问题

对于一个类而言,只要其中包含有初始化列表的构造函数,编译器在编译使用{}语法的构造时会最倾向于调用初始化列表构造函数,哪怕做类型转换也在所不惜,哪怕有类型最佳匹配的普通构造函数或移动构造函数也会被劫持

class Widget {
public:
Widget(int i, bool b);
Widget(int i, double d);
Widget(std::initializer_list<long double> il);
operator float() const;
}; Widget w1(10, true); // 使⽤小括号初始化
//调⽤第⼀个构造函数
Widget w2{10, true}; // 使⽤花括号初始化
// 调⽤第三个构造函数
// (10 和 true 转化为long double)
Widget w3(10, 5.0); // 使⽤小括号初始化
// 调⽤第二个构造函数
Widget w4{10, 5.0}; // 使⽤花括号初始化
// 调⽤第三个构造函数
// (10 和 5.0 转化为long double)
Widget w5(w4); // 使⽤小括号,调⽤拷⻉构造函数
Widget w6{w4}; // 使⽤花括号,调⽤std::initializer_list构造函数
Widget w7(std::move(w4)); // 使⽤小括号,调⽤移动构造函数
Widget w8{std::move(w4)}; // 使⽤花括号,调⽤std::initializer_list构造函数

编译器这种热衷于把括号初始化与初始化列表构造函数匹配的行为,会导致一些莫名其妙的错误

class Widget {
public:
Widget(int i, bool b);
Widget(int i, double d);
Widget(std::initializer_list<bool> il); // element type is now bool
… // no implicit conversion funcs
};
Widget w{10, 5.0}; //错误!要求变窄转换,int(10)double(5.0)无法转换为bool类型

只有在没有办法把{}中实参的类型转化为初始化列表时,编译器才会回到正常的函数决议流程中

⽐如我们在构造函数中⽤std::initializer_list<std::string>代替std::initializer_list<bool> ,这时⾮std::initializer_list构造函数将再次成为函数决议的候选者,因为没有办法把int和bool转换为std::string:

class Widget {
public:
Widget(int i, bool b);
Widget(int i, double d);
Widget(std::initializer_list<std::string> il);

};
Widget w1(10, true); // 使⽤小括号初始化,调⽤第⼀个构造函数
Widget w2{10, true}; // 使⽤花括号初始化,调⽤第⼀个构造函数
Widget w3(10, 5.0); // 使⽤小括号初始化,调⽤第⼆个构造函数
Widget w4{10, 5.0}; // 使⽤花括号初始化,调⽤第⼆个构造函数

{}空初始化列表会发生什么

假如{}内是空的,类中既有默认构造函数,也有初始化列表构造函数,此时{}会被视为没有实参,而不是一个空的初始化列表,因此会调用默认构造函数。如果就是想调用初始化列表构造函数,这应该使用{{}}的方式

class Widget {
public:
Widget();
Widget(std::initializer_list<int> il);
...
};
Widget w1; // 调⽤默认构造函数
Widget w2{}; // 同上
Widget w3(); // 最令⼈头疼的解析!声明⼀个函数
Widget w4({}); // 调⽤std::initializer_list
Widget w5{{}}; // 同上

初始化列表带来的vector的坑

std::vector<int> v1(10, 20); 	//使⽤⾮std::initializer_list
//构造函数创建⼀个包含10个元素的std::vector
//所有的元素的值都是20
std::vector<int> v2{10, 20}; //使⽤std::initializer_list
//构造函数创建包含两个元素的std::vector
//元素的值为10和20

初始化列表构造函数问题带来的两点启示

  • 作为类库作者,如果在构造函数中重载了一个或多个初始化列表构造函数,要考虑用户使用{}初始化的情况,最好避免类似std::vector中的情况。应该尽可能做到用户无论用小括号还是花括号进行初始化都不会产生区别。一定要慎重考虑新出现的初始化列表构造函数对其他构造函数的影响!!!
  • 作为类库使用者,必须认真的考虑小括号和花括号之间选择创建对象的方式,最好选择其中一个从一而终

【C++】初始化列表构造函数VS普通构造函数的更多相关文章

  1. C++-什么时候需要在类的构造函数中使用初始化列表

    1,如果基类没有default构造函数,则意味着其不能自己初始化.如果其被派生,派生类的构造函数要负责调用基类的构造函数,并传递给它需要的参数.下例中Base 2,如果类成员没有默认构造函数.下例中E ...

  2. c++ 关于类构造函数的初始化列表

    除了性能问题之外,有些时场合初始化列表是不可或缺的,以下几种情况时必须使用初始化列表 常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面 引用类型,引用必须在定义的时候初始化,并且不能重 ...

  3. 【校招面试 之 C/C++】第1题 为什么优先使用构造函数的初始化列表

    1.首先看一个例子: #include<iostream> using namespace std; class Test1 { public: Test1() // 无参构造函数 { c ...

  4. C++ 构造函数_初始化列表

    构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: class Student { public: //构造函数初始化列表 Stude ...

  5. C++初阶(类的访问权限以及封装+this指针+构造函数+析构函数+拷贝构造函数+参数列表+友元+内部类)

    面向过程与面向对象 C语言是面向过程的,关注的是过程(函数),分析出求解问题的步骤,通过函数调用逐步解决问题. C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成. ...

  6. C++类的成员初始化列表的相关问题

    在以下四中情况下,要想让程序顺利编译,必须使用成员初始化列表(member initialization list): 1,初始化一个引用成员(reference member): 2,初始化一个常量 ...

  7. c++,初始化列表

    类对象的构造顺序是这样的: a.分配内存,调用构造函数时,隐式/显示的初始化各数据成员 b.进入构造函数后在构造函数中执行一般计算 1.初始化类的成员有两种方式,一是使用初始化列表,二是在构造函数体内 ...

  8. C++ 初始化列表(转)

    转载自:http://www.cnblogs.com/graphics/archive/2010/07/04/1770900.html 何谓初始化列表 与其他函数不同,构造函数除了有名字,参数列表和函 ...

  9. C++: 类成员初始化列表语法

      类的成员初始化列表的初始化的基本语法,类的构造函数还可以运用此语法为其变量初始化: class Class { private: int a; int b; char ch; public: Cl ...

  10. C++ 成员初始化列表

    1.什么是成员初始化列表 #include<iostream> #include<string> using namespace std; class Weapon { pri ...

随机推荐

  1. msfconsole的使用

    msfconsole是metasploit中的一个工具: msfconsole集成了很多漏洞的利用的脚本,并且使用起来很简单的网络安全工具 在终端输入msfconsole命令即可进入msf的控制台,m ...

  2. Bootstarp5第三弹

    五.文字排版 <.h1>-<.h6> <div class="container"> <h1>文字排版</h1> < ...

  3. Spring MVC 和 Struts 的区别是什么?

    1. 拦截机制的不同 Struts2 是类级别的拦截,每次请求就会创建一个 Action,和 Spring 整合时 Struts2 的 ActionBean 注入作用域是原型模式 prototype, ...

  4. 设计模式(二十八)----综合应用-自定义Spring框架-Spring简单回顾

    1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao接口及其子实现类 public ...

  5. 机器学习算法(八):基于BP神经网络的乳腺癌的分类预测

    机器学习算法(八):基于BP神经网络的乳腺癌的分类预测 1.算法简介和应用 1.1 算法简介 BP(Back Propagation)网络是1986年由Rumelhart和McCelland为首的科学 ...

  6. 2023年数字化经济与管理科学国际学术会议(CDEMS2023)

    基本信息 大会官网:www.cdems.org 大会时间:2023年4月21-23日 大会地点:中国开封 截稿时间:2023年4月16日(此处有变动) 接受/拒稿通知:投稿后1周 收录检索:CPCI, ...

  7. 方差分析1—单因素方差分析(R语言)

    方差分析是由英国著名统计学家:R.A.Fisher推导,也叫F检验,用于多个样本间均数的比较(分析类别变量.有序变量).当包含的因子是解释变量时,关注的重点通常会从预测转向组别差异的分析.方差分析是一 ...

  8. flask-login使用方法

    烧瓶登录 Flask-Login 为 Flask 提供用户会话管理.它处理登录.注销和长时间记住用户会话的常见任务. 它会: 将活动用户的 ID 存储在Flask Session中,让您轻松登录和注销 ...

  9. MySQL笔记之Checkpoint机制

    CheckPoint是MySQL的WAL和Redolog的一个优化技术. 一.Checkpoint机制 CheckPoint做了什么事情?将缓存池中的脏页刷回磁盘. checkpoint定期将db b ...

  10. DG修复:修改密码文件导致归档不应用

    问题描述:重启完备库,之后发现主备同步状态异常,mrp进程状态显示applying log,但是v$datagaurd_stats视图中查询到归档日志并没有在应用.主库切换归档,可以正常传输过来,但是 ...