序言:
目录
(一)C++11简介
(二)统一的列表初始化
1、{}初始化
2、std::initializer_list
(三)声明
1、auto
2、decltype
3、nullptr
(四)范围for循环
(五)STL中一些变化
总结
在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习。C++11增加的语法特性非常篇幅非常多,我们这里没办法一 一讲解,所以本节课程主要讲解实际中比较实用的语法。
【知识拓展】
1998年是C++标准委员会成立的第一年,本来计划以后每5年视实际需要更新一次标准,C++国际标准委员会在研究C++ 03的下一个版本的时候,一开始计划是2007年发布,所以最初这个标准叫C++ 07。但是到06年的时候,官方觉得2007年肯定完不成C++ 07,而且官方觉得2008年可能也完不成。最后干脆叫C++ 0x。x的意思是不知道到底能在07还是08还是09年完成。结果2010年的时候也没完成,最后在2011年终于完成了C++标准。所以最终定名为C++11。
接下来,我们将正式开始学习C++11 的第一个新增特性——有关统一的列表初始化的相关知识!
使用大括号 {} 进行初始化可以在不同的情况下提供一致的行为,并且具有一些特殊的初始化规则和语义。
下面是一些 C++11 中使用大括号进行初始化的示例:
int main()
{
int x{ 42 }; // 使用大括号直接初始化 x 为 42
string str{ "Hello" }; // 使用大括号直接初始化字符串对象
cout << x << endl;
cout << str << endl;
return 0;
}
输出展示:
int main()
{
int x{}; // 使用大括号进行默认初始化,x 的值为 0
string str{}; // 使用大括号进行默认初始化,str 为空字符串
cout << x << endl;
cout << str << endl;
return 0;
}
输出展示:
在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:
struct Point
{
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}
而在C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
代码展示:
int main()
{
int x1 = 1;
int x2{ 2 };
cout << x1 << endl;
cout << x2 << endl;
return 0;
}
输出展示:
因此,对于上述结构体和数组的初始化操作,在C++11中可以转化为下面这样:
struct Point
{
int _x;
int _y;
};
int main()
{
//c++98
/*int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };*/
//c++11
int array1[]{ 1, 2, 3, 4, 5 };
int array2[5]{ 0 };
Point p{ 1, 2 };
return 0;
}
输出展示:
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;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// old style
Date d1(2022, 1, 1);
// C++11支持的列表初始化,这里会调用构造函数初始化
Date d2{ 2022, 1, 2 };
Date d3 = { 2022, 1, 3 };
return 0;
}
输出展示:
【解释说明】
【小结】
std::initializer_list 是 C++11 引入的标准库类型,用于方便地表示初始化列表。它是一个轻量级的容器类,用于存储一组相同类型的值。
使用 std::initializer_list 可以将一组值作为参数传递给函数或构造函数,或者用于对象的初始化。它的语法类似于大括号 {}
初始化,但提供了更灵活的传递和使用方式。
下面是一些 std::initializer_list 的常见用法:
void Point(initializer_list values) {
for (const auto& value : values) {
cout << value << " ";
}
cout << endl;
}
int main() {
Point({ 1, 2, 3, 4 }); // 使用初始化列表作为参数
return 0;
}
输出展示:
class MyClass {
public:
MyClass(initializer_list values) {
// 在构造函数中使用初始化列表
for (const auto& value : values) {
// 处理每个值
cout << value << " ";
}
}
};
int main()
{
MyClass obj({ 1, 2, 3, 4 }); // 使用初始化列表作为构造函数参数
return 0;
}
输出展示:
int main()
{
initializer_list values = { 1, 2, 3, 4 };
for (const auto& value : values) {
// 处理每个值
cout << value << " ";
}
return 0;
}
输出展示:
std::initializer_list 的主要优点是它提供了一种简洁、直观的方式来传递初始化列表,特别适用于带有不确定数量参数的函数或构造函数。它允许以类似于标准容器的方式进行遍历和访问其中的值。
那是因为在 C++11 中,学从vector 提供了以下构造函数:
注意:std::initializer_list 是一个只读容器,不能进行元素的插入、删除或修改。它的元素类型是常量,因此通常会使用 const auto&
来遍历元素。
1.插入报错
2.删除报错
3.修改报错
【小结】
c++11提供了多种简化声明的方式,尤其是在使用模板时。
在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。
下面是一些关于 auto
的使用示例:
int main()
{
auto num = 42; // 推断 num 的类型为 int
auto str = "Hello"; // 推断 str 的类型为 const char*
auto arr = std::vector(); // 推断 vec 的类型为 std::vector
return 0;
}
输出展示:
在这些示例中,auto
关键字根据变量的初始化表达式推断出变量的类型,并相应地声明变量。
auto add(int a, int b) {
return a + b;
}
在这个示例中,auto
用于推断函数的返回类型。根据返回表达式的类型,编译器会自动推断出函数的返回类型。
【小结】
auto
推断的类型是在编译时确定的,而不是运行时。这意味着使用 auto
声明的变量在编译时会根据初始化表达式的类型进行类型推断,然后在后续的代码中被视为具有确定的类型。auto
是根据初始化表达式推断类型,因此在一些情况下可能会导致意外的类型推断结果或不明确的类型。在这些情况下,可以使用显式的类型声明或其他更具体的类型推断工具(例如类型转换操作符)来消除歧义。关键字decltype将变量的类型声明为表达式指定的类型。
代码举例:
int main()
{
const int x = 1;
double y = 2.2;
decltype(x * y) ret; // ret的类型是double
decltype(&x) p; // p的类型是 const int*
cout << typeid(ret).name() << endl;
cout << typeid(p).name() << endl;
return 0;
}
输出展示:
由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示
整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
这个我们在前面的课程中已经进行了非常详细的讲解,这里就不进行讲解了。
新容器
用橘色圈起来是C++11中的一些几个新容器,但是实际最有用的是unordered_map和
unordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家了解一下即可
以上便是本期关于 C++11 新特性的介绍。以上内容在校招中属于了解内容,大家知道会用即可!