C++ Primer Plus 第18章笔记

第18章 探讨C++新标准

18.1 复习前面介绍过的C++11功能

18.1.1 新类型

C++11新增了类型long long 和unsigned long long,以支持64位(或更宽)的整型;新增了类型char16_t和char32_t,以支持16位和32位的字符表示;还新增了“原始”字符串。

18.8.2 统一的初始化

C++11扩大了用大括号括起的列表(初始化列表)的适用范围,使其可用于所有内置类型和用户定义的类型(即类对象)。使用初始化列表时,可添加等号(=),也可不添加。

然而,如果类有将模板std::initializer_list作为参数的构造函数,则只有该构造函数可以使用列表初始化形式。

初始化列表语法可防止缩窄,即禁止将数值赋给无法存储它的数值变量。但允许转换为更宽的类型。

18.1.3 声明

C++11将auto用于实现自动类型推断。这要求进行显式初始化,让编译器能够将变量的类型设置为初始值的类型。

关键字decltype将变量的类型声明为表达式指定的类型。
decltype (x) y
expr返回左值,得到该类型的左值引用;expr返回右值,得到该类型。

C++11可以在函数名和参数列表后面指定返回类型:
f2(double, int) -> double;

模板别名:using=
对于冗长或复杂的标识符,如果能够创建其别名将很方便。
using=可用于模板部分具体化,但typedef不能。

C++11新增了关键字nullptr,用于表示空指针;它是指针类型,不能转换为整型类型。为向后兼容,C++11仍允许使用0来表示空指针,因此表达式nullptr==0为true。

18.1.4 智能指针

C++11据弃了auto_ptr,并新增了三种智能指针:unique_ptr、shared_ptr、weak_ptr。

18.1.5 异常规范方面的修改

指出函数不会引发异常有一定的价值,他们为C++11添加了关键字noexcept。
void f875(short, short) noexcept;

18.1.6 作用域内枚举

C++11新增了作用域内枚举。这种枚举使用class或struct定义:
enum class new1{yes, no, maybe};
新枚举要求进行显式限定,以免发生名称冲突。
new1::yes

18.1.7 对类的修改

C++引入了关键字explicit,以禁止单参数构造函数导致的自动转换。

C++11拓展了explicit的这种用法,使得可对转换函数做类似的处理。
类内初始化:可使用等号或大括号版本的初始化,但不能使用圆括号版本的初始化。

class people {
    int year = 10;
};

18.1.8 模板和STL方面的修改

基于范围的for循环:

double prices [5] = {4.99, 10.99, 6.87, 7.99, 8.49};
for (auto x : prices)
    std::cout << x << std::endl;

C++11新增了STL容器forward_list,unordered_map,unordered_multimap,unordered_set unordered_multiset。容器forward_list是一种单向链表,只能沿一个方向遍历;与双向链接的list容器相比,它更简单,在占用存储空间方面更经济。其他四种容器都是使用哈希表实现的。
C++11还新增了模板array。要实例化这种模板,可指定元素类型和固定的元素数:
std::array ar;

C++11新增了STL方法cbegin()、cend()、crbegin()和crend()。只不过这些新方法将元素视为const。
除传统的复制构造函数和常规赋值运算符外,STL容器现在还有移动构造函数和移动赋值运算符。

C++11添加了两个函数(begin()和end()),它们都接受valarray作为参数,并返回选代器。

C++11摒弃export。

C++11要求在声明嵌套模板时使用空格将尖括号分开。

18.1.9 右值引用

C++11新增了右值引用,这是使用&&表示的。右值引用可关联到右值,即可出现在赋值表达式右边,但不能对其应用地址运算符的值。

18.2 移动语义和右值引用

18.2.1 为何需要移动语义

移动构造函数,它使用右值引用作为参数,该引用关联到右值实参,移动构造函数可能修改其实参,这意味着右值引用,参数不应是const。

18.2.4 赋值

适用于构造函数的移动语义考虑也适用于赋值运算符。

18.3 新的类功能

18.3.1 特殊的成员函数

如果您提供了析构函数、复制构造函数或复制赋值运算符,编译器将不会自动提供移动构造函数和移动赋值运算符。
如果您提供了移动构造函数或移动赋值运算符,编译器将不会自动提供复制构造函数和复制赋值运算符。

18.3.2 默认的方法和禁用的方法

C++11让您可使用关键字default显式地声明这些方法的默认版本
Someclass &operator= (const Someclass &) = default;
另一方面,关键字delete可用于禁止编译器使用特定方法。
关键字default只能用于6个特殊成员函数,但delete可用于任何成员函数。

18.3.3 委托构造函数

C++11允许您在一个构造函数的定义中使用另一个构造函数。这被称为委托。
Notes::Notes() : Notes(0, 0.01, "Oh") {}

18.3.4 继承构造函数

可以使用using让派生类包含基类的函数,如:using BASE::FUNC
C++11将这种方法用于构造函数。这让派生类继承基类的所有构造函数(默认构造函数、复制构造函数和移动构造函数除外),但不会使用与派生类构造函数的特征标匹配的构造函数。

18.3.5 管理虚方法:override和final

在C++11中,可使用虚说明符override指出您要覆盖一个虚函数:将其放在参数列表后面。如果声明与基类方法不匹配,编译器将视为错误。
您可能想禁止派生类覆盖特定的虚方法,为此可在参数列表后面加上final。
说明符override和final并非关键字,而是具有特殊含义的标识符。

18.4 Lambda函数

18.4.1比较函数指针、函数符和Lambda函数

函数与Lambda函数的差别有两个:使用[]替代了函数名;没有声明返回类型。返回类型相当于使用decltyp根据返回值推断得到的。如果lambda不包含返回语句,推断出的返回类型将为void。
[] (int x) {return x % 3 == 0;}
返回类型后置语法:
[] (double x) ->double (int y = x; return x - y;)

18.4.2 为何使用lambda

但并非必须编写lambda两次,而可给lambda指定一个名称,并使用该名称两次:
auto mod3 = [] (int x) {return x % 3 == 0;}

lambad可访问作用域内的任何动态变量;要捕获要使用的变量,可将其名称放在中括号内。如果只指定了变量名,如[z],将按值访问变量;如果在名称前加上&,如[&count],将按引用访问变量。[&]让您能够按引用访问所有动态变量,而[=]让您能够按值访问所有动态变量。还可混合使用这两种方式,

18.5 包装器

模板function是在头文件functional中声明的,它从调用特征标的角度定义了一个对象,可用于包装调用特征标相同的函数指针、函数对象或lambda表达式。
std::function fdci;
可以将任何函数指针、函数对象或lambda表达式赋给它。

18.6 可变参数模板

C++11提供了一个用省略号表示的元运算符(meta-operator),让您能够声明表示模板参数包的标识符,模板参数包基本上是一个类型列表。同样,它还让您能够声明表示函数参数包的标识符,而函数参数包基本上是一个值列表。其语法如下:

template <typename ... Args>
void show_list1(Args ... args)

将函数参数包展开,对列表中的第一项进行处理,再将余下的内容传递给递归调用,以此类推,直到列表为空。

void show_list3() {}
template <typename T, typename ... Args>
void show_list3(T value, Args ... args)
{
    show_list3(args ...);
}

你可能感兴趣的:(笔记,c++)