C++11 - 部分特性(基础)
本节内容包含列表初始化,initializer_list的使用,decltype,nullptr
1.列表初始化
C++98(包括C语言中)允许使用花括号对数组或者结构体元素进行列表初始值的设定
struct Point
{
int x;
int y;
};
int main()
{
int arry[] = { 1, 2, 3, 4, 5 };
Point p = { 0, 1 };
return 0;
}
C++11扩大了括号括起的列表(初始化列表)的范围,使其可以省略等号
struct Point
{
int x;
int y;
};
int main()
{
int arry[]{ 1, 2, 3, 4, 5 };
Point p{ 0, 1 };
// C++11的列表初始化也可以适用于new表达式中
// 开一个数组,并初始化为1,2,3,4
int* pa = new int[4]{ 1, 2, 3, 4 };
return 0;
}
结论:C++11支持的列表初始化对于自定义类型去使用都是调用对方的构造函数
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
Date(const Date& d)
{
cout << "Date(const Date & d1)" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 1, 1); // old style
// C++11支持的列表初始化,这里调用的是Date构造
Date d2{ 2022, 1, 2 };
Date d3 = { 2022, 1, 3 };
// 这里调用的是Date的拷贝构造
Date d4(d3);
return 0;
}
2.initializer_list的使用
C++11中多数容器都内置了
initializer_list
,其作用是支持{ }给容器赋值以
vector<int> v为例
,如果没有initializer_list
,赋值的时候则需要v.push_back(val)
的方式不断向内部插入值,但是内置了initializer_list
,就可以直接用vector<int> v = {1, 2, 3, 4};
的方式赋值,这样就可以支持STL的容器进行大括号赋值
std::initializer_list
作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=
的参数,这样就可以用大括号赋值。结论:
initializer_list
的出现方便了STL容器的初始化
struct Point
{
public:
Point(int x, int y)
:_x(x)
,_y(y)
{
cout << "Point(int x, int y) -- 构造" << endl;
}
Point(const Point& p)
{
_x = p._x;
_y = p._y;
cout << "Point(const Point& p) -- 拷贝构造" << endl;
}
Point& operator=(const Point& p)
{
if (this != &p)
{
_x = p._x;
_y = p._y;
}
cout << "Point& operator=(const Point& p) -- 赋值" << endl;
}
private:
int _x;
int _y;
};
int main()
{
// 区分不同的规则
vector<int> v = { 1, 2, 3, 4, 5 }; // 调用的是initializer_list的vector构造函数
// 隐式类型转换 - 调用两次构造函数,首先构造{1, 1},在用他去构造p
// 调用两次构造,编译器会优化成直接构造,所以结果是一次构造
Point p = { 1, 2 }; // 编译器的优化
return 0;
}
模拟实现的
vector
,内部集成initializer_list
,遍历并push即可实现大括号赋值
vector(initializer_list<T> lt)
{
reserve(lt.size());
for (auto e : lt)
{
push_back(e);
}
}
3.decltype
decltype
和typeid
的区别:typeid
仅能查看变量的类型,不能作为类型再去定义变量,decltype
推出对象的类型,再定义变量,或者作为模板实参
int main()
{
auto a = 10;
cout << typeid(a).name() << endl;
// decltype推出对象的类型,再定义变量,或者作为模板实参
decltype(a) b;
vector<decltype(a)> v1;
const int x = 1;
double y = 2.2;
cout << typeid(x * y).name() << endl;
vector<decltype(x * y)> v2;
return 0;
}
4.nullptr
由于C++中
NULL
被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr
,用于表示空指针
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
END!!!