普通构造函数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. [极客大挑战 2019]PHP 1

    进入后提示我们网页有备份文件,这边使用爆破工具,网页会down掉 随便随便猜了一下www.zip,成功下载源码 常见的网页备份有 .git ~ .swp .swo .bak .zip 还不知道是什么题 ...

  2. 脏牛-Linux内核提权

    漏洞范围 下载地址:https://github.com/FireFart/dirtycow 有一点可以在意,dirty.c内置在了kali中,使用命令searchsploit dirty可以搜索 也 ...

  3. 使用shell 方式对 vcenter 进行补丁升级

    使用shell 方式对 vcenter 进行补丁升级 背景:最近VMware官网发布了最新的VMware vCenter Server 7.0 iso补丁文件,为了安全起故此对vCenter 进行安全 ...

  4. windows下使用route添加路由

    1,首先在"运行"窗口输入cmd(按WIN+R打开运行窗口),然后回车进入命令行. 2,在命令行下输入route命令,会有对应的提示信息. ROUTE [-f] [-p] [-4| ...

  5. java多线程--2 静态代理、Lambda表达式

    java多线程--2 静态代理.Lambda表达式 静态代理 package com.ssl.demo02; //静态代理 //真实对象和代理对象都要实现同一个接口 //代理对象必须要代理真实角色 / ...

  6. 商城网站毕业设计( Python +Vue)

    网站介绍 基于 python 开发的电子商城网站,平台采用 B/S 结构,后端采用主流的 Python 语言进行开发,前端采用主流的 Vue.js 进行开发.这是给师弟开发的毕业设计. 整个平台包括前 ...

  7. idea创建Spring项目时选择Maven还是Spring initializr?

    今天在使用idea创建Spring项目时不知道选择Maven还是Spring initializr 接着都实验了一下,其实本质是一样的,使用"spring initializr"创 ...

  8. Lodash中常用函数,不建议经常使用,容易让人变懒忘了原生函数

    1.N次循环 <script type="text/javascript"> console.log('------- javascript -------'); // ...

  9. Linux文件系统故障,Input/output error

    事情是这样的,在启动某一个应用程序的时候,出现 Input/output error 的报错,磁盘以及目录无法使用的情况下,进行了重启,重启完成后是可以正常使用的,过一段时间后就会再次出现这个问题,一 ...

  10. pysimplegui之进度表one_line_progress_meter

    我们的代码中都有循环.'等待,看着文本窗口中滚动过去的计数器不是很快乐吗?一行代码如何获得一个进度表,其中包含有关您的代码的统计信息? one_line_progress_meter(title, c ...