【C++11】列表初始化【{ }使用详解】
文章目录
- 前言
- 1. {}对内置类型和自定义类型
- 1.1 内置类型
- 1.2 自定义类型
- 1.2.1 多参数的隐式类型转化
- 2. initializer_list
- 2.1 initializer_list的类型
- 2.2 在STL中的使用
- 2.3 区别隐式类型转化和initializer_list
前言
在C++98中,标准允许使用花括号{}
对数组或者结构体元素进行统一的列表初始值设定。比如:
//C语言风格
struct Point
{int x;int y;
};int main()
{//结构体:struct Point p = { 1, 2 };//数组:int arr[10] = { 1, 2, 3 };return 0;
}
C++委员会认为,利用
{}
的初始化方式十分“优雅”,于是对于{}
的初始化方式进行了升级!
下面我们就来认识{}
的初始化方式。
1. {}对内置类型和自定义类型
-
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
-
总结:
一切皆可使用
{}
进行初始化。
1.1 内置类型
例1:
int main()
{int x = 1; //原始写法//C++11可以的写法:int y = { 1 }; //新写法,有=int z{ 1 }; //新写法,无=int x1{ 1 }, y1{ 2 }; //同类型变量连续定义//对于new来说:int* p = new int(1); //旧写法int* ptr = new int{ 1 }; //新写法return 0;
}
1.2 自定义类型
- 关于自定义类型的讨论,我们可以从构造函数角度进行学习。
例2:
//已包含头文件
class Point
{
public:Point(int x = 0, int y = 0) //默认构造:_x(x), _y(y){printf("( %d, %d )\n", x, y); //方便观察}int _x;int _y;
};int main()
{Point p1(1, 1); // 原始写法Point p2 = { 2, 2 }; //C++11有赋值写法 ?Point p3{ 3, 3 }; //C++11无赋值写法return 0;
}
- 对于自定义类型的构造无一列外需要调用构造函数。
说明自定义类型使用
{}
本质也是将参数传递个这个对象的构造函数。
1.2.1 多参数的隐式类型转化
观察上面例2代码:Point p2 = { 2, 2 };
是否感觉到特别的熟悉?
我们有如下例3:
class A
{
public:A(int x){cout << x << endl;}
};int main()
{A a = 1;return 0;
}
-
上面代码中的:
A a = 1;
是一个单参数的隐式类型转化。即:编译器先用
1
构造了一个A
类对象,然后再用这个A
类对象来拷贝构造给a
。但是编译器直接实现优化:用1
直接构造a
对象!
所以现在我们回到刚刚那个问题:Point p2 = { 2, 2 };
就是一个隐式类型转化!!!
编译器先利用{2, 2}
构造一个Point
的临时对象,然后再拷贝构造给p2
对象。但是编译器实现了优化,直接利用{2, 2}
构造,例如:p1,p3
一致。
- 证明:
explicit
关键字(禁止隐式类型转化)
足以说明
p2
的构造是采用了隐式类型转化。
explict详情
2. initializer_list
- initializer_list介绍文档
initializer_list
(初始化列表)是C++11引入的一种轻量级模板类,用于简化初始化操作。它允许以统一的方式处理花括号{}
列表初始化,常用于构造函数、函数参数或返回值的初始化场景。
2.1 initializer_list的类型
例4:
//已包含头文件
int main()
{auto il = { 10, 20, 30 };cout << typeid(il).name() << endl;return 0;
}
- 注:
typeid
后面会谈到,这里作用:用变量构造一个类,name
函数获取变量类型。
2.2 在STL中的使用
- list构造中的initializer_list
- vector构造中的initializer_list
- map构造中的initializer_list
- vector赋值拷贝中的initializer_list
- ……
例5:
//头文件已正确包含
int main()
{map<string, string> m = { make_pair("香蕉", "banana"), make_pair("苹果", "apple") };cout << m["香蕉"] << endl;return 0;
}
2.3 区别隐式类型转化和initializer_list
例6:
//头文件已正确包含
class Point
{
public:Point(int x = 0, int y = 0) //默认构造:_x(x), _y(y){printf("( %d, %d )\n", x, y); //方便观察}int _x;int _y;
};int main()
{vector<int> v = { 1,2,2,3,4 }; //代码一Point p = { 1, 2 }; //代码二return 0;
}
-
代码一:
vector<int> v = { 1,2,2,3,4 };
是先利用{}
进行构造一个initializer_list
的对象,再用来构造v
对象。(自定义的
vector
没有写initializer_list
的构造函数是无法完成构造的,就能说明这一点) -
代码二:
Point p = { 1, 2 };
编译器优化直接构造。
完。
- 希望这篇文章能够帮助你!