【C++】C++11--- 列表初始化|关键字

目录

前言

列表初始化

创建对象时的列表初始化

单参数隐式类型转换

多参数的隐式类型转换

new表达式中使用列表初始化

列表初始化适用于STL 容器

模板类initializer_list

关键字auto

关键字decltype

关键字nullptr


前言

C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟,相比于C++98,C++11带来了数量可观的变化,其中包含了约140个新特性,以及对C++98标准中约600个缺陷的修正,这使得C++11更像是从C++98中孕育出的一种新语言;相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更加强大,而且能提升程序员的开发效率;

官方文档:C++11 - cppreference.com

列表初始化

C++98中,标准允许使用花括号{}对数组元素或者结构体元素进行统一的列表初始值设定;

struct person
{
	const char* name;
	int age;
};
int main()
{
	int array1[] = { 1, 2, 3, 4, 5 };
	//整型数组未指定初始化内容,按照默认值0初始化数组未指定的内容
	int array2[3] = { 1 };
	person p = { "Linda", 23 };
	return 0;
}

监视窗口:

C++11扩大了{}(初始化列表)的使用范围,使其可用于所有的内置类型与自定义类型,使用初始化列表时,可以添加等号,也可以不添加;

struct person
{
	const char* name;
	int age;
};
int main()
{
	int array1[]{ 1, 2, 3, 4, 5 };
	//整型数组未指定初始化内容,按照默认值0初始化数组未指定的内容
	int array2[3]{ 1 };
	person p{ "Linda", 23 };
	return 0;
}

监视窗口:

创建对象时的列表初始化

class Date
{
public:
	//构造函数
	Date(int year,int month,int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{
		cout << "调用构造函数" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d2(2024, 6, 1);//c++ 98
	Date d1 = { 2024,5,1 };//c++ 11 (不推荐使用)
  	return 0;
}

运行结果:

单参数隐式类型转换

class Date
{
public:
	//单参数(缺省)的构造函数
	/*Date(int year=2000)
		:_year(year)
	{
		cout << "调用缺省单参数构造函数" << endl;
	}*/

	//单参数(无参)的构造函数
	Date(int year)
		:_year(year)
	{
		cout << "调用单参数(无参)构造函数" << endl;
	}
private:
	int _year;
};
int main()
{
	Date d1(2000);
	//d1-->自定义类型
	//10-->整型
	d1 = 10;//类型转换 
	return 0;
}

结论:无参的单参数构造函数与缺省的单参数构造函数皆支持隐式类型转换;

多参数的隐式类型转换

class Date
{
public:
	//Date(int year, int month, int day)//(不支持隐式类型转换)
	//Date(int year, int month, int day=1)//(不支持隐式类型转换)
	//Date(int year, int month=1, int day=1)//(支持隐式类型转换)
	Date(int year=1, int month = 1, int day = 1)//(支持隐式类型转换)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "调用构造函数" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2022);//2022 1 1
	//2023-->int类型 d1-->Date类型
	d1 = 2023;//2023 1 1
	return 0;
}

结论:

  1. 多参数第一个参数无默认值,其余参数皆存在默认值支持隐式类型转换;
  2. 多参数所有参数都存在默认值支持隐式类型转换;
int main()
{
	//单参数
	string s1("abcdef");//直接调用构造函数
	string s2 = "abcdef";//隐式类型转换(单参数构造函数支持隐式类型转换) 
	//首先用常量字符串构造一个const string类型的匿名对象,然后匿名对象拷贝构造s2;
	//最后编译器优化为直接构造

	//多参数
	//构造+拷贝构造-->编译器优化为直接构造
	Date d3 = { 2024,5,1};//本质:隐式类型转换(多参数构造函数支持隐式类型转换)
	return 0;
}

new表达式中使用列表初始化

class Date
{
public:
	//全缺省的默认构造函数
	Date(int year=2024,int month=5,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{
		cout << "调用构造函数" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 3, 1);
	Date d2(2024, 4, 1);
	//自定义类型数组未指定初始化内容,按照自定义类型的默认构造函数初始化数组未指定的内容;
	Date* darr1 = new Date[3]{ d1,d2 };// c++ 98
	Date* darr2 = new Date[3]{ {2024, 3, 1},{2024, 4, 1},{2024, 5, 1} }; //c++ 11(推荐使用)
  	return 0;
}

监视窗口:

列表初始化适用于STL 容器

C++98中,对于自定义类型并不支持如下写法

vector<int> v = {1,2,3,4,5};//注:容器v中的参数个数是可变的

但是C++11中可以支持容器v中的参数为任意多个,本质原因为C++11中为各个STL容器提供了参数类型为initializer_list的构造函数;

模板类initializer_list

auto il = { 1, 2, 3, 4, 5 , 6, 7, 8};
//{}初始化列表传递给auto且初始化列表的数据类型为int,则il对象的类型initializer_list<int>

常用接口

int main()
{
	auto il = { 1, 2, 3, 4, 5, 6, 7, 8 };
	cout << "size=" << il.size() << endl;
	initializer_list<int>::iterator lit = il.begin();
	while (lit != il.end())
	{
		cout << *lit << " ";
		++lit;
	}
	cout << endl;
	return 0;
}

运行结果:

initializer_list的底层结构为两个指针,一个指向常量数组的起始位置,另一个指向常量数组的结束位置的下一个位置,那么vector的构造函数参数类型为initializer_list,如何支持容器vector中的参数为任意多个?

template <class T>
class vector
{
	typedef T* iterator;
	typedef const T* const_iterator;
public:
	//如何进行范围形式的初始化
	vector(initializer_list<T>& il)
	{
		_start = new T[il.size()];
		_finish = _start + il.size();
		_endofstorage = _start + il.size();
		iterator vit = _start;
		//利用迭代器进行赋值
		typename initializer_list<T>::iterator lit = il.begin();
		while (lit != il.end())
		{
			*vit++ = *lit++;
		}
	}
private:
	iterator _start;
	iterator _finish;
	iterator _endofstorage;
};

关键字auto

C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto也就毫无价值;

C++11中废弃auto原来的用法,将其用于实现自动类型推断,如此便要求必须进行显示初始化让编译器将定义对象的类型设置为初始化值的类型;

map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };

map<string, string>::iterator it1 = dict.begin();
//使用auto关键字避免手写特别长的迭代器类型
auto it2 = dict.begin();

注意:禁用auto做返回值的用法;

关键字decltype

auto使用时必须对auto声明的类型进行初始化,否则编译器不能推导出auto的实际类型;

  • 作用:decltype 关键字用于获取表达式的类型;
  • 用法:decltype(express) 用于获取表达式 express的类型,并将其作为变量的类型或者函数的返回类型;
  • 特点:decltype 不执行表达式,而是在编译期间分析表达式的类型

decltype 的多种应用场景

  • 获取变量类型:通过分析变量的初始化表达式,推导出变量的类型;
  • 获取表达式类型:根据表达式的类型,获取相应的类型信息;
int x = 5;
decltype(x) a = 10; // 推导 a 的类型为 int

std::vector<int> v = {1, 2, 3, 4, 5};
decltype(v.size()) size = v.size(); //推导size的类型为 std::vector<int>::size_type

关键字nullptr

由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能表示指针常量,又能表示整形常量;所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针;

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

欢迎大家批评指正,博主会持续输出优质内容,谢谢各位观众老爷观看,码字画图不易,希望大家给个一键三连支持~ 你的支持是我创作的不竭动力~

  • 32
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小呆瓜历险记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值