C++高级编程(第4版)

C++高级编程(第4版)"

作者:[美]马克·葛瑞格尔(MarcGregoire)著徐志超曹瑜译
ISBN:9787302526315
定价:¥138
字数:千字
页数:
出版时间:2019.04.01
开本:
版次:1-1
装帧:
出版社:清华大学出版社
简介

·展现C++思考方式,以便充分利用该语言中影响深远的功能来开发高效的解决方案。

·阐释鲜为人知的元素,披露避开常见陷阱的技巧,分享提示、技巧和方案,以帮助提高工作效率和软件性能。

·列出富有挑战、贴近实用、具有多种用途的代码段,可根据需要将这些代码段移植到任何项目中。

·浓墨重彩地描述C++17的新功能,如结构化绑定、嵌套的名称空间和constexpr if等。

·深入讨论C++17新的标准库功能,比如string_view、optional类、并行算法和文件系统API等。

前言

前 言

多年来,C++都是编写性能卓越、功能强大的企业级面向对象程序的事实标准语言。尽管C++语言已经风靡全球,但这种语言却非常难完全掌握。专业C++程序员使用一些简单但高效的技术,这些技术并未出现在传统教材中;即使是经验丰富的C++程序员,也未必完全了解C++中某些很有用的特性。

编程书籍往往重点描述语言的语法,而不是语言在真实世界中的应用。典型的C++教材在每一章中介绍语言中的大部分知识,讲解语法并列举示例。《C++高级编程(第4版)》不遵循这种模式。《C++高级编程(第4版)》并不讲解语言的大量细节并给出少量真实世界的场景,而是教你如何在真实世界中使用C++。《C++高级编程(第4版)》还会讲解一些鲜为人知的让编程更简单的特性,以及区分编程新手和专业程序员的编程技术。

读者对象

就算使用C++已经多年,也仍可能不熟悉C++的一些高级特性,或仍不具有使用这门语言的完整能力。也许你编写过实用的C++代码,但还想学习更多有关C++中设计和良好编程风格的内容。也许你是C++新手,想在入门时就掌握“正确”的编程方式。《C++高级编程(第4版)》能满足上述需求,将你的C++技能提升到专业水准。

因为《C++高级编程(第4版)》专注于从对C++具有基本或中等了解水平蜕变为一名专业C++程序员的过程,所以《C++高级编程(第4版)》假设你对该语言具有一定程度的认识。第1 章涵盖C++的一些基础知识,可以当成复习材料,但是不能替代实际的语言培训和语言使用手册。如果刚开始接触C++,但有很丰富的C、Java 或C#语言经验,那么应该能从第1 章获得所需的大部分知识。

不管属于哪种情况,都应该具有很好的编程基础。应该知道循环、函数和变量。应该知道如何组织一个程序,而且应该熟悉基本技术,例如递归。应该了解一些常见的数据结构(例如队列)以及有用的算法(例如排序和搜索)。不需要预先了解有关面向对象编程的知识—— 这是第5章讲解的内容。

还应该熟悉开发代码时使用的编译器。稍后将简要介绍Microsoft Visual C++和GCC 这两种编译器。要了解其他编译器,请参阅编译器自带的指南。

《C++高级编程(第4版)》主要内容

阅读《C++高级编程(第4版)》是学习C++语言的一种方法,通过阅读《C++高级编程(第4版)》既能提升编码质量,又能提升编程效率。《C++高级编程(第4版)》贯穿对C++17 新特性的讨论。这些新的C++17 特性并不是分散在各章中,而是穿插于全书,在有必要的情况下,所有例子都已更新为使用这些新特性。

《C++高级编程(第4版)》不仅讲解C++语法和语言特性,还强调编程方法论、可重用的设计模式以及良好的编程风格。《C++高级编程(第4版)》讲解的方法论覆盖整个软件开发过程——从设计和编码,到调试以及团队协作。这种方法可让你掌握C++语言及其独有特性,还能在大型软件开发中充分利用C++语言的强大功能。

想象一下有人学习了C++的所有语法但没有见过一个C++例子的情形。他所了解的知识会让他处于非常危险的境地。如果没有示例的引导,他可能会认为所有源代码都要放在程序的main()函数中,还有可能认为所有变量都应该为全局变量—— 这些都不是良好的编程实践。

专业的C++程序员除了理解语法外,还要正确理解语言的使用方式。他们知道良好设计的重要性、面向对象编程的理论以及使用现有库的最佳方式。他们还开发了大量有用的代码并了解可重用的思想。

通过阅读和理解《C++高级编程(第4版)》的内容,你也能成为一名专业的C++程序员。你在C++方面的知识会得到扩充,将接触到鲜为人知和常被误解的语言特性。你还将领略面向对象设计,掌握卓越的调试技能。最重要的或许是,通过阅读《C++高级编程(第4版)》,你的头脑中有了大量“可重用”思想,可将这种思想贯彻到日常工作中。

有很多好的理由让你努力成为一名专业的C++程序员,而非只是泛泛了解C++。了解语言的真正工作原理有助于提升代码质量。了解不同的编程方法论和过程可让你更好地和团队协作。探索可重用的库和常用的设计模式可提升日常工作效率,并帮助避免白费力气地重复工作。所有这些学习课程都在帮助你成为更优秀的程序员,同时成为更有价值的雇员。

《C++高级编程(第4版)》结构

《C++高级编程(第4版)》包括5 部分。

第I 部分“专业的C++简介”是C++基础速成教程,能确保读者掌握C++的基础知识。在速成教程后,第I 部分深入讨论字符串和字符串视图的使用,因为字符串在示例中应用广泛。第I 部分的最后一章介绍如何编写清晰易读的C++代码。

第II 部分“专业的C++软件设计”介绍C++设计方法论。你会了解到设计的重要性、面向对象方法论和代码重用的重要性。

第III 部分“专业的C++编码方法”从专业角度概述C++技术。你将学习在C++中管理内存的最佳方式,如何创建可重用的类,以及如何利用重要的语言特性,例如继承。你还会学习这门语言的一些不同寻常之处、输入输出技术、错误处理、字符串本地化和正则表达式的使用,讨论如何实现运算符重载,如何编写模板。这一部分还讲解C++标准库,包括容器、迭代器和算法。你还会学习C++标准中的其他一些库,例如处理时间、随机数和文件系统的库。

第IV 部分“掌握C++的高级特性”讲解如何最大限度地使用C++。《C++高级编程(第4版)》这一部分揭示C++中神秘的部分,并描述如何使用这些更高级的特性。你将学习如何定制和扩充标准库以满足自己的需求、高级模板编程的细节(包括模板元编程),以及如何通过多线程编程来充分利用多处理器和多核系统。

第V 部分“C++软件工程”重点介绍如何编写企业级质量的软件。相关的主题如下:当今编程组织使用的工程实践,如何编写高效的C++代码,软件测试概念(如单元测试和回归测试),C++程序的调试技术,如何在自己的代码中融入设计技术、框架和概念性的面向对象设计模式,跨语言和跨平台代码的解决方案,等等。

《C++高级编程(第4版)》最后是4 个附录。附录A 列出在C++技术面试中取得成功的指南,附录B 是带注解的参考文献列表,附录C 总结C++标准中的头文件,附录D 简要介绍UML(Unified Modeling Language,统一建模语言)。

《C++高级编程(第4版)》没有列出C++中每个类、方法和函数的参考。Peter Van Weert 和Marc Gregoire 撰写的C++ Standard Library Quick Reference 是C++标准库提供的所有重要数据结构、算法和函数的浓缩版。附录B 列出了更多参考资料。下面是两个很好的在线参考。

www.cppreference.co m

可使用这个在线参考,也可下载其离线版本,在没有连接到互联网时使用。

www.cplusplus.com/reference/

《C++高级编程(第4版)》正文中提到“标准库参考资料”时,就是指上述C++参考资料。

使用《C++高级编程(第4版)》的条件

要使用《C++高级编程(第4版)》,只需要一台带有C++编译器的计算机。《C++高级编程(第4版)》只关注C++中的标准部分,而没有任何编译器厂商相关的扩展。

《C++高级编程(第4版)》包含C++17 标准引入的新特性。在撰写《C++高级编程(第4版)》时,有些编译器还不能完全支持C++17 的所有新特性。

可使用任意C++编译器。如果还没有C++编译器,可下载一个免费的。这有许多选择。例如,对于Windows,可下载Microsoft Visual Studio 2017 Community Edition,这个版本免费且包含Visual C++;对于Linux,可使用GCC 或Clang,它们也是免费的。

下面将简要介绍如何使用Visual C++和GCC。可参阅相关的编译器文档来了解更多信息。

Microsoft Visual C++

首先需要创建一个项目。启动VC++,单击File | New | Project,在左边的项目模板树中选择Visual C++ |Win32,再在窗口中间的列表中选择Win32 Console Application(或Windows Console Application)模板。在底部指定项目的名称、保存位置,单击OK。

这会打开一个向导,单击Next 按钮,选择Console Application 和Empty Project,再单击Finish 按钮。注意,你可能看不到向导,具体取决于使用的VC++ 2017 版本。相反,将自动创建一个新的项目,其中包含4 个文件:stdafx.h、stdafx.cpp、targetver.h 和<projectname>.cpp。如果遇到这种情况,而你想要编译源代码文件(取自从配套网站下载的《C++高级编程(第4版)》源代码压缩文件),则必须在Solution Explorer(选择View | Solution Explorer)中选择这些文件,然后删除它们。

加载新项目后,就会在Solution Explorer 中看到项目文件列表。如果这个停靠窗口不可见,可选择View |Solution Explorer。在Solution Explorer 中右击项目名,再选择Add | New Item 或Add | Existing Item,就可以给项目添加新文件或已有文件。

使用Build | Build Solution 编译代码。没有编译错误后,就可以使用Debug | Start Debugging 运行了。

如果程序在查看输出之前就退出了,可使用Debug | Start without Debugging。这会在程序末尾暂停,以便查看输出。

在撰写《C++高级编程(第4版)》期间,Visual C++ 2017 尚未自动启用C++17 功能。要启用C++17 功能,可在Solution Explorer窗口中右击项目,然后单击Properties。在Properties 窗口中,选择Configuration Properties | C/C++ | Language,根据使用的Visual C++版本,将C++ Language Standard 选项设置为ISO C++17 Standard 或ISO C++ Latest Draft Standard。仅当项目至少包含一个.cpp 文件时,才能访问这些选项。

Visual C++支持“预编译的头文件”,这个话题超出了《C++高级编程(第4版)》的讨论范围。通常而言,如果编译器支持的话,建议使用预编译的头文件。但是,从《C++高级编程(第4版)》网站下载的源代码文件不使用预编译的头文件,因此,只有禁用这项功能才能使这些代码正确编译。在Solution Explorer 窗口中右击项目,选择Properties。在Properties 窗口中,找到Configuration Properties | C/C++ | Precompiled Headers,将Precompiled Header 选项设置为Not Using Precompiled Headers。

GCC

用自己喜欢的任意文本编辑器创建源代码,保存到一个目录下。要编译代码,可打开一个终端,运行如下命令,指定要编译的所有.cpp 文件:

gcc -lstdc++ -std=c++17 -o <executable_name> <source1.cpp> [source2.cpp ... ]

-std=c++17 用于告诉GCC 启用C++17 支持。

例如,可切换到包含代码的目录,运行如下命令来编译第1 章的AirlineTicket 示例:

g cc –lstdc++ -std=c++17 -o AirlineTicket AirlineTicket.cpp AirlineTicketTest.cpp

没有编译错误后,就可以使用如下命令运行了:

. /AirlineTicket

勘误表

尽管我们已经尽了各种努力来保证文章或代码中不出现错误,但错误总是难免的。如果在《C++高级编程(第4版)》中找到错误,例如拼写错误或代码错误,请告诉我们,我们将非常感激。通过勘误表,可以让其他读者避免受挫,当然,这还有助于提供更高质量的信息。

请给wkservice@vip.163.com 发电子邮件,我们就会检查你提供的信息,如果是正确的,我们将在《C++高级编程(第4版)》的后续版本中采用。

要在网站上找到《C++高级编程(第4版)》的勘误表,可登录http://www.wrox.com,通过Search 工具或书名列表查找《C++高级编程(第4版)》,然后在《C++高级编程(第4版)》的细目页面上,单击Book Errata 链接。在这个页面上可查看Wrox 编辑已提交和粘贴的所有勘误项。完整的图书列表还包括每《C++高级编程(第4版)》的勘误表,网址是www.wrox.com/misc-pages/booklist.shtml。

源代码

读者在学习《C++高级编程(第4版)》中的示例时,可以手动输入所有代码,也可使用《C++高级编程(第4版)》附带的源代码文件。《C++高级编程(第4版)》使用的所有源代码都可以从《C++高级编程(第4版)》合作站点www.wiley.com/go/proc++4e 下载。

另外,也可进入http://www.wrox.com/dynamic/books/download.aspx 上的Wrox 代码下载主页,查看《C++高级编程(第4版)》和其他Wrox 图书的所有代码。

还可通过扫描《C++高级编程(第4版)》封底的二维码来下载源代码。

提示:

由于许多图书的书名都十分类似,因此按ISBN 搜索是最简单的,《C++高级编程(第4版)》英文版的ISBN 是978-1-119-42130-6。

下载代码后,只需要用自己喜欢的解压缩软件进行解压缩即可。

目录

目 录

第 I 部分 专业的C++简介

第1 章 C++和标准库速成   2

1.1 C++基础知识   2

1.1.1 小程序“hello world”    3

1.1.2 名称空间   .5

1.1.3 字面量   6

1.1.4 变量   7

1.1.5 运算符   8

1.1.6 类型   10

1.1.7 条件语句   12

1.1.8 逻辑比较运算符   14

1.1.9 函数   15

1.1.10 C风格的数组   16

1.1.11 std::array   17

1.1.12 std::vector    17

1.1.13 结构化绑定   18

1.1.14 循环   18

1.1.15 初始化列表   19

1.1.16 这些都是基础   19

1.2 深入研究C++   20

1.2.1 C++中的字符串   20

1.2.2 指针和动态内存   20

1.2.3 const的多种用法   24

1.2.4 引用   24

1.2.5 异常   25

1.2.6 类型推断   26

1.3 作为面向对象语言的C++    27

1.3.1 定义类   27

1.3.2 使用类   29

1.4 统一初始化   29

1.5 标准库   31

1.6 第一个有用的C++程序   31

1.6.1 雇员记录系统   32

1.6.2 Employee类   32

1.6.3 Database类   34

1.6.4 用户界面    36

1.6.5 评估程序    38

1.7 本章小结    38

第2 章 使用string 和string_view    39

2.1 动态字符串    39

2.1.1 C风格的字符串    39

2.1.2 字符串字面量    41

2.1.3 C++ std::string类    42

2.1.4 std::string_view类    46

2.1.5 非标准字符串    47

2.2 本章小结    47

第3 章 编码风格   48

3.1 良好外观的重要性    48

3.1.1 事先考虑    48

3.1.2 良好风格的元素    49

3.2 为代码编写文档    49

3.2.1 使用注释的原因    49

3.2.2 注释的风格    52

3.3 分解       55

3.3.1 通过重构分解    56

3.3.2 通过设计来分解    56

3.3.3 本书中的分解    56

3.4 命名       56

3.4.1 选择恰当的名称    57

3.4.2 命名约定    57

3.5 使用具有风格的语言特性    59

3.5.1 使用常量    59

3.5.2 使用引用代替指针    59

3.5.3 使用自定义异常    59

3.6 格式       60

3.6.1 关于大括号对齐的争论    60

3.6.2 关于空格和圆括号的争论    61

3.6.3 空格和制表符    61

3.7 风格的挑战    61

3.8 本章小结       62

第 II 部分 专业的C++软件设计

第4 章 设计专业的C++程序   64

4.1 程序设计概述    64

4.2 程序设计的重要性    65

4.3 C++设计的特点    66

4.4 C++设计的两个原则    67

4.4.1 抽象       67

4.4.2 重用       68

4.5 重用代码       69

4.5.1 关于术语的说明    69

4.5.2 决定是否重用代码    70

4.5.3 重用代码的策略    71

4.5.4 绑定第三方应用程序    74

4.5.5 开放源代码库    75

4.5.6 C++标准库    76

4.6 设计一个国际象棋程序    76

4.6.1 需求       76

4.6.2 设计步骤    77

4.7 本章小结       80

第5 章 面向对象设计   82

5.1 过程化的思考方式    82

5.2 面向对象思想    83

5.2.1 类       83

5.2.2 组件       83

5.2.3 属性       83

5.2.4 行为       84

5.2.5 综合考虑    84

5.3 生活在对象世界里    85

5.3.1 过度使用对象    85

5.3.2 过于通用的对象    85

5.4 对象之间的关系    86

5.4.1 “有一个”关系    86

5.4.2 “是一个”关系(继承)    87

5.4.3 “有一个”与“是一个”的区别   88

5.4.4 not-a关系    90

5.4.5 层次结构    91

5.4.6 多重继承    91

5.4.7 混入类     92

5.5 抽象        93

5.5.1 接口与实现     93

5.5.2 决定公开的接口    93

5.5.3 设计成功的抽象    94

5.6 本章小结       95

第6 章 设计可重用代码    96

6.1 重用哲学       96

6.2 如何设计可重用代码    97

6.2.1 使用抽象    97

6.2.2 构建理想的重用代码     98

6.2.3 设计有用的接口    102

6.2.4 SOLID原则      106

6.3 本章小结       106

第 III 部分 专业的C++编码方法

第7 章 内存管理      108

7.1 使用动态内存     108

7.1.1 如何描绘内存     109

7.1.2 分配和释放    110

7.1.3 数组        111

7.1.4 使用指针    116

7.2 数组-指针的对偶性    117

7.2.1 数组就是指针      117

7.2.2 并非所有指针都是数组   119

7.3 低级内存操作   119

7.3.1 指针运算    119

7.3.2 自定义内存管理    120

7.3.3 垃圾回收    120

7.3.4 对象池     121

7.4 智能指针       121

7.4.1 unique_ptr     122

7.4.2 shared_ptr     124

7.4.3 weak_ptr     125

7.4.4 移动语义    126

7.4.5 enable_shared_from_this     127

7.4.6 旧的、过时的/取消的auto_ptr   127

7.5 常见的内存陷阱     127

7.5.1 分配不足的字符串     127

7.5.2 访问内存越界     128

7.5.3 内存泄漏    128

7.5.4 双重删除和无效指针    131

7.6 本章小结       131

第8 章 熟悉类和对象   132

8.1 电子表格示例介绍    132

8.2 编写类       133

8.2.1 类定义    133

8.2.2 定义方法   135

8.2.3 使用对象   137

8.3 对象的生命周期   138

8.3.1 创建对象   138

8.3.2 销毁对象   149

8.3.3 对象赋值   149

8.3.4 编译器生成的复制构造函数和复制赋值运算符    151

8.3.5 复制和赋值的区别    151

8.4 本章小结       153

第9 章 精通类与对象     154

9.1 友元      154

9.2 对象的动态内存分配   155

9.2.1 Spreadsheet类   155

9.2.2 使用析构函数释放内存   157

9.2.3 处理复制和赋值    158

9.2.4 使用移动语义处理移动   162

9.2.5 零规则    167

9.3 与方法有关的更多内容   167

9.3.1 静态方法   167

9.3.2 const方法   168

9.3.3 方法重载   169

9.3.4 内联方法   170

9.3.5 默认参数   171

9.4 不同的数据成员类型   172

9.4.1 静态数据成员   172

9.4.2 静态常量数据成员    173

9.4.3 引用数据成员   174

9.4.4 常量引用数据成员    175

9.5 嵌套类       175

9.6 类内的枚举类型   176

9.7 运算符重载   177

9.7.1 示例:为SpreadsheetCell实现加法   177

9.7.2 重载算术运算符    179

9.7.3 重载比较运算符    181

9.7.4 创建具有运算符重载的类型   181

9.8 创建稳定的接口   182

9.9 本章小结         184

第10 章 揭秘继承技术     185

10.1 使用继承构建类   185

10.1.1 扩展类   186

10.1.2 重写方法    188

10.2 使用继承重用代码    194

10.2.1 WeatherPrediction类    194

10.2.2 在派生类中添加功能    195

10.2.3 在派生类中替换功能    196

10.3 利用父类       196

10.3.1 父类构造函数    196

10.3.2 父类的析构函数    197

10.3.3 使用父类方法    198

10.3.4 向上转型和向下转型    200

10.4 继承与多态性    201

10.4.1 回到电子表格    201

10.4.2 设计多态性的电子表格单元格  201

10.4.3 SpreadsheetCell基类    202

10.4.4 独立的派生类    203

10.4.5 利用多态性    204

10.4.6 考虑将来    205

10.5 多重继承       206

10.5.1 从多个类继承    206

10.5.2 名称冲突和歧义基类    207

10.6 有趣而晦涩的继承问题    209

10.6.1 修改重写方法的特征    209

10.6.2 继承的构造函数    211

10.6.3 重写方法时的特殊情况    214

10.6.4 派生类中的复制构造函数和赋值运算符    219

10.6.5 运行时类型工具    220

10.6.6 非public继承    221

10.6.7 虚基类    221

10.7 本章小结       222

第11 章 理解灵活而奇特的C++    223

11.1 引用       223

11.1.1 引用变量    224

11.1.2 引用数据成员    225

11.1.3 引用参数    225

11.1.4 将引用作为返回值    226

11.1.5 右值引用    226

11.1.6 使用引用还是指针    227

11.2 关键字的疑问    229

11.2.1 const关键字    229

11.2.2 static关键字    232

11.2.3 非局部变量的初始化顺序 235

11.2.4 非局部变量的销毁顺序    235

11.3 类型和类型转换    235

11.3.1 类型别名    235

11.3.2 函数指针的类型别名    236

11.3.3 方法和数据成员的指针的类型别名   238

11.3.4 typedef    238

11.3.5 类型转换    239

11.4 作用域解析    242

11.5 特性       243

11.5.1 [[noreturn]]特性    243

11.5.2 [[deprecated]]特性    244

11.5.3 [[fallthrough]]特性    244

11.5.4 [[nodiscard]]特性    244

11.5.5 [[maybe_unused]]特性    244

11.5.6 供应商专用特性    245

11.6 用户定义的字面量    245

11.7 头文件       246

11.8 C 的实用工具    247

11.8.1 变长参数列表    247

11.8.2 预处理器宏     249

11.9 本章小结       250

第12 章 利用模板编写泛型代码   251

12.1 模板概述       252

12.2 类模板       252

12.2.1 编写类模板    252

12.2.2 尖括号    258

12.2.3 编译器处理模板的原理    258

12.2.4 将模板代码分布在多个文件中    258

12.2.5 模板参数    260

12.2.6 方法模板    263

12.2.7 类模板的特例化    266

12.2.8 从类模板派生    267

12.2.9 继承还是特例化    268

12.2.10 模板别名     268

12.3 函数模板       269

12.3.1 函数模板的特例化     270

12.3.2 函数模板的重载    271

12.3.3 类模板的友元函数模板    271

12.3.4 对模板参数推导的更多介绍   272

12.3.5 函数模板的返回类型     272

12.4 可变模板       274

12.5 本章小结       274

第13 章 C++ I/O 揭秘   275

13.1 使用流       275

13.1.1 流的含义    276

13.1.2 流的来源和目的地    276

13.1.3 流式输出    277

13.1.4 流式输入    280

13.1.5 对象的输入输出    285

13.2 字符串流       286

13.3 文件流       287

13.3.1 文本模式与二进制模式    287

13.3.2 通过seek()和tell()在文件中转移  288

13.3.3 将流链接在一起    289

13.4 双向I/O       290

13.5 本章小结       291

第14 章 错误处理      292

14.1 错误与异常    292

14.1.1 异常的含义    292

14.1.2 C++中异常的优点    293

14.1.3 我们的建议    294

14.2 异常机制       294

14.2.1 抛出和捕获异常    295

14.2.2 异常类型    296

14.2.3 按const和引用捕获异常对象   297

14.2.4 抛出并捕获多个异常    297

14.2.5 未捕获的异常    299

14.2.6 noexcept     300

14.2.7 抛出列表(已不赞成使用/已删除)   300

14.3 异常与多态性    301

14.3.1 标准异常体系    301

14.3.2 在类层次结构中捕获异常   302

14.3.3 编写自己的异常类    303

14.3.4 嵌套异常    305

14.4 重新抛出异常    306

14.5 堆栈的释放与清理    307

14.5.1 使用智能指针    308

14.5.2 捕获、清理并重新抛出    309

14.6 常见的错误处理问题    309

14.6.1 内存分配错误    309

14.6.2 构造函数中的错误   311

14.6.3 构造函数的function-try-blocks  312

14.6.4 析构函数中的错误    314

14.7 综合应用       315

14.8 本章小结       318

第15 章 C++运算符重载   319

15.1 运算符重载概述    319

15.1.1 重载运算符的原因    320

15.1.2 运算符重载的限制   320

15.1.3 运算符重载的选择   320

15.1.4 不应重载的运算符   322

15.1.5 可重载运算符小结   322

15.1.6 右值引用   324

15.1.7 关系运算符   325

15.2 重载算术运算符   325

15.2.1 重载一元负号和一元正号运算符   325

15.2.2 重载递增和递减运算符   326

15.3 重载按位运算符和二元逻辑运算符   327

15.4 重载插入运算符和提取运算符    327

15.5 重载下标运算符   328

15.5.1 通过operator[]提供只读访问     330

15.5.2 非整数数组索引   330

15.6 重载函数调用运算符   331

15.7 重载解除引用运算符   332

15.7.1 实现operator*    333

15.7.2 实现operator->   333

15.7.3 operator.*和operator ->*的含义   334

15.8 编写转换运算符   334

15.8.1 使用显式转换运算符解决多义性问题   335

15.8.2 用于布尔表达式的转换          335

15.9 重载内存分配和内存释放运算符   337

15.9.1 new和delete的工作原理   337

15.9.2 重载operator new和operator delete    338

15.9.3 显式地删除/默认化operator new和operator delete   340

15.9.4 重载带有额外参数的operator new和operator delete    340

15.9.5 重载带有内存大小参数的operator delete    340

15.10 本章小结   341

第16 章 C++标准库概述    342

16.1 编码原则      343

16.1.1 使用模板   343

16.1.2 使用运算符重载   343

16.2 C++标准库概述   343

16.2.1 字符串   343

16.2.2 正则表达式   344

16.2.3 I/O流   344

16.2.4 智能指针   344

16.2.5 异常   344

16.2.6 数学工具    344

16.2.7 时间工具    345

16.2.8 随机数    345

16.2.9 初始化列表    345

16.2.10 pair和tuple     345

16.2.11 optional、variant和any     345

16.2.12 函数对象    346

16.2.13 文件系统    346

16.2.14 多线程    346

16.2.15 类型特质    346

16.2.16 标准整数类型    346

16.2.17 容器    346

16.2.18 算法    351

16.2.19 标准库中还缺什么    358

16.3 本章小结       358

第17 章 理解容器与迭代器    359

17.1 容器概述       359

17.1.1 对元素的要求    360

17.1.2 异常和错误检查    361

17.1.3 迭代器    361

17.2 顺序容器       363

17.2.1 vector     363

17.2.2 vector<bool>特化    376

17.2.3 deque    377

17.2.4 list       377

17.2.5 forward_list    380

17.2.6 array    381

17.3 容器适配器    382

17.3.1 queue    382

17.3.2 priority_queue    384

17.3.3 stack    386

17.4 有序关联容器    387

17.4.1 pair工具类    387

17.4.2 map    388

17.4.3 multimap    393

17.4.4 set        396

17.4.5 multiset     397

17.5 无序关联容器/哈希表    397

17.5.1 哈希函数    397

17.5.2 unordered_map     399

17.5.3 unordered_multimap     401

17.5.4 unordered_set/unordered_multiset  402

17.6 其他容器       402

17.6.1 标准C风格数组    402

17.6.2 string    403

17.6.3 流       403

17.6.4 bitset     403

17.7 本章小结       407

第18 章 掌握标准库算法   408

18.1 算法概述       408

18.1.1 find()和find_if()算法    409

18.1.2 accumulate()算法    410

18.1.3 在算法中使用移动语义    411

18.2 std::function     411

18.3 lambda 表达式    413

18.3.1 语法    413

18.3.2 泛型lambda表达式    415

18.3.3 lambda捕捉表达式    415

18.3.4 将lambda表达式用作返回类型   415

18.3.5 将lambda表达式用作参数     416

18.3.6 标准库算法示例    416

18.4 函数对象       417

18.4.1 算术函数对象    417

18.4.2 比较函数对象    418

18.4.3 逻辑函数对象    419

18.4.4 按位函数对象    419

18.4.5 函数对象适配器    419

18.4.6 std::invoke()    422

18.4.7 编写自己的函数对象    423

18.5 算法详解       423

18.5.1 迭代器    424

18.5.2 非修改序列算法    424

18.5.3 修改序列算法    427

18.5.4 操作算法    433

18.5.5 交换算法    434

18.5.6 分区算法    435

18.5.7 排序算法    436

18.5.8 二叉树搜索算法    436

18.5.9 集合算法    437

18.5.10 最大/最小算法    439

18.5.11 并行算法    440

18.5.12 数值处理算法    440

18.6 算法示例:审核选民登记    442

18.6.1 选民登记审核问题描述    442

18.6.2 auditVoterRolls()函数    442

18.6.3 getDuplicates()函数    443

18.6.4 测试auditVoterRolls()函数   443

18.7 本章小结       444

第19 章 字符串的本地化与正则表达式    445

19.1 本地化       445

19.1.1 本地化字符串字面量    445

19.1.2 宽字符    446

19.1.3 非西方字符集    446

19.1.4 转换    447

19.1.5 locale和facet    448

19.2 正则表达式    450

19.2.1 ECMAScript语法    451

19.2.2 regex库    455

19.2.3 regex_match()     456

19.2.4 regex_search()    458

19.2.5 regex_iterator    458

19.2.6 regex_token_iterator     459

19.2.7 regex_replace()    461

19.3 本章小结       462

第20 章 其他库工具   463

20.1 ratio 库       463

20.2 chrono 库       465

20.2.1 持续时间    465

20.2.2 时钟    468

20.2.3 时点    469

20.3 生成随机数    470

20.3.1 随机数引擎    471

20.3.2 随机数引擎适配器    472

20.3.3 预定义的随机数引擎和引擎适配器   472

20.3.4 生成随机数    473

20.3.5 随机数分布    474

20.4 optional       476

20.5 variant       477

20.6 any        478

20.7 元组       479

20.7.1 分解元组    481

20.7.2 串联    481

20.7.3 比较    482

20.7.4 make_from_tuple()    482

20.7.5 apply()    483

20.8 文件系统支持库    483

20.8.1 path     483

20.8.2 directory_entry     484

20.8.3 辅助函数    484

20.8.4 迭代    484

20.9 本章小结      485

第 IV 部分 掌握C++的高级特性

第21 章 自定义和扩展标准库    488

21.1 分配器      488

21.2 流适配器      489

21.2.1 输出流迭代器   489

21.2.2 输入流迭代器   490

21.3 迭代器适配器   490

21.3.1 反向迭代器   490

21.3.2 插入迭代器   491

21.3.3 移动迭代器   492

21.4 扩展标准库   493

21.4.1 扩展标准库的原因   493

21.4.2 编写标准库算法   493

21.4.3 编写标准库容器   495

21.5 本章小结      519

第22 章 高级模板       520

22.1 深入了解模板参数   520

22.1.1 深入了解模板类型参数   520

22.1.2 template template参数介绍   522

22.1.3 深入了解非类型模板参数   524

22.2 模板类部分特例化     525

22.3 通过重载模拟函数部分特例化   527

22.4 模板递归      528

22.4.1 N维网格:初次尝试   529

22.4.2 真正的N维网格   529

22.5 可变参数模板   531

22.5.1 类型安全的变长参数列表    532

22.5.2 可变数目的混入类   533

22.5.3 折叠表达式   534

22.6 模板元编程   535

22.6.1 编译时阶乘   536

22.6.2 循环展开   536

22.6.3 打印元组   537

22.6.4 类型trait   539

22.6.5 模板元编程结论   545

22.7 本章小结      545

第23 章 C++多线程编程    546

23.1 多线程编程概述   547

23.1.1 争用条件   548

23.1.2 撕裂    549

23.1.3 死锁    549

23.1.4 伪共享    550

23.2 线程       550

23.2.1 通过函数指针创建线程    550

23.2.2 通过函数对象创建线程    551

23.2.3 通过lambda创建线程    552

23.2.4 通过成员函数创建线程    553

23.2.5 线程本地存储    553

23.2.6 取消线程    553

23.2.7 从线程获得结果    553

23.2.8 复制和重新抛出异常    554

23.3 原子操作库    555

23.3.1 原子类型示例    556

23.3.2 原子操作    557

23.4 互斥       558

23.4.1 互斥体类    558

23.4.2 锁       560

23.4.3 std::call_once    561

23.4.4 互斥体对象的用法示例    562

23.5 条件变量       565

23.5.1 假唤醒    565

23.5.2 使用条件变量    565

23.6 future       566

23.6.1 std::promise和std::future     567

23.6.2 std::packaged_task    567

23.6.3 std::async    568

23.6.4 异常处理    568

23.6.5 std::shared_future     569

23.7 示例:多线程的Logger 类    570

23.8 线程池       573

23.9 线程设计和最佳实践    573

23.10 本章小结    574

第 V 部分 C++软件工程

第24 章 充分利用软件工程方法    576

24.1 过程的必要性    576

24.2 软件生命周期模型    577

24.2.1 瀑布模型    577

24.2.2 生鱼片模型    578

24.2.3 螺旋类模型    579

24.2.4 敏捷    581

24.3 软件工程方法论    581

24.3.1 UP        581

24.3.2 RUP    582

24.3.3 Scrum    583

24.3.4 极限编程    584

24.3.5 软件分流    587

24.4 构建自己的过程和方法    588

24.4.1 对新思想采取开放态度    588

24.4.2 提出新想法    588

24.4.3 知道什么行得通、什么行不通   588

24.4.4 不要逃避    588

24.5 源代码控制    588

24.6 本章小结       590

第25 章 编写高效的C++程序   591

25.1 性能和效率概述    591

25.1.1 提升效率的两种方式    592

25.1.2 两种程序    592

25.1.3 C++是不是低效的语言    592

25.2 语言层次的效率    592

25.2.1 高效地操纵对象    593

25.2.2 预分配内存    596

25.2.3 使用内联方法和函数    596

25.3 设计层次的效率    596

25.3.1 尽可能多地缓存    596

25.3.2 使用对象池    597

25.4 剖析       599

25.4.1 使用gprof的剖析示例    600

25.4.2 使用Visual C++ 2017 的剖析示例   605

25.5 本章小结       608

第26 章 熟练掌握测试技术   609

26.1 质量控制       609

26.1.1 谁负责测试    610

26.1.2 bug的生命周期    610

26.1.3 bug跟踪工具    611

26.2 单元测试       612

26.2.1 单元测试方法    613

26.2.2 单元测试过程    613

26.2.3 实际中的单元测试    616

26.3 高级测试       622

23.3.1 集成测试    622

26.3.2 系统测试    623

26.3.3 回归测试    623

26.4 用于成功测试的建议    624

26.5 本章小结       624

第27 章 熟练掌握调试技术   625

27.1 调试的基本定律    625

27.2 bug 分类学    626

27.3 避免bug       626

27.4 为bug 做好规划    626

27.4.1 错误日志    626

27.4.2 调试跟踪    627

27.4.3 断言    633

27.4.4 崩溃转储    633

27.5 静态断言       634

27.6 调试技术       634

27.6.1 重现bug    635

27.6.2 调试可重复的bug    635

27.6.3 调试不可重现的bug     635

27.6.4 调试退化    636

27.6.5 调试内存问题    636

27.6.6 调试多线程程序    640

27.6.7 调试示例:文章引用    640

27.6.8 从ArticleCitations示例中总结出的教训    648

27.7 本章小结       649

第28 章 使用设计技术和框架   650

28.1 容易忘记的语法    651

28.1.1 编写类    651

28.1.2 派生类    652

28.1.3 使用“复制和交换”惯用语法   652

28.1.4 抛出和捕捉异常    653

28.1.5 读取文件    654

28.1.6 写入文件    654

28.1.7 写入模板类    654

28.2 始终存在更好的方法    655

28.2.1 RAII     655

28.2.2 双分派    657

28.2.3 混入类    660

28.3 面向对象的框架    662

28.3.1 使用框架    662

28.3.2 MVC范型    662

28.4 本章小结       663

第29 章 应用设计模式   664

29.1 迭代器模式    665

29.2 单例模式       665

29.2.1 日志记录机制    665

29.2.2 实现单例    666

29.2.3 使用单例    668

29.3 抽象工厂模式   668

29.3.1 示例:模拟汽车工厂   669

29.3.2 实现工厂   670

29.3.3 使用工厂   671

29.3.4 工厂的其他用法   672

29.4 代理模式      672

29.4.1 示例:隐藏网络连接问题    673

29.4.2 实现代理   673

29.4.3 使用代理   674

29.5 适配器模式   674

29.5.1 示例:改编Logger类   674

29.5.2 实现适配器   675

29.5.3 使用适配器   675

29.6 装饰器模式   675

29.6.1 示例:在网页中定义样式    676

29.6.2 装饰器的实现   676

29.6.3 使用装饰器    677

29.7 责任链模式   677

29.7.1 示例:事件处理   678

29.7.2 实现责任链   678

29.7.3 没有层次结构的责任链   679

29.8 观察者模式   680

29.8.1 实现观察者    680

29.8.2 实现可观察类   681

29.8.3 使用观察者     681

29.9 本章小结       682

第30 章 开发跨平台和跨语言应用程序 683

30.1 跨平台开发    683

30.1.1 架构问题     683

30.1.2 实现问题     686

30.1.3 平台专用功能    686

30.2 跨语言开发    687

30.2.1 混用C和C++    687

30.2.2 改变范型     688

30.2.3 链接C代码    690

30.2.4 从C#调用C++代码    691

30.2.5 在Java中使用JNI调用C++代码   692

30.2.6 从C++代码调用脚本    694

30.2.7 从脚本调用C++代码    694

30.2.8 从C++调用汇编代码    696

30.3 本章小结          696

附录A C++面试        697

附录B 带注解的参考文献    713

附录C 标准库头文件    721

附录D UML 简介       726

作者简介

编辑推荐

这本讲解C++17 的著作将帮助读者全面透彻地掌握C++语言的功能,包罗C++语言的一切,分享真实范例,展现C++17 的新工具和功能,详述如何在真实世界中使用C++,揭示新版C++带来的显著变化,解密C++中鲜为人知的特性,探索编程方法论、可重用的设计模式和良好的编程风格,阐述如何设计可充分利用C++语言功能的高效解决方案。本书深入探讨C++语言功能集的更复杂元素,并讲解避开常见陷阱的技巧。本书提供详尽的编程指南,紧贴实际,是编程人员深入挖掘C++的理想工具。

作者寄语

Marc Gregoire 是一名软件工程师,毕业于比利时鲁文大学,拥有计算机科学工程硕士学位。之后,他在

鲁文大学获得人工智能专业的优等硕士学位。完成学业后,他开始为软件咨询公司Ordina Belgium 工作。他曾在

Siemens 和Nokia Siemens Networks为大型电信运营商提供有关在Solaris 上运行关键2G和3G软件的咨询服务。

这份工作要求与来自南美、美国、欧洲、中东、非洲和亚洲的国际团队合作。Marc 目前担任Nikon Metrology

(www.nikonmetrology.com)的软件架构师;Nikon Metrology 是Nikon 的分公司,是领先的精密光学仪器和3D 扫

描软件供应商。

Marc 的主要技术专长是C/C++,特别是Microsoft VC++和MFC 框架。他还擅长在Windows 和Linux 平台

上开发24×7 小时运行的C++程序,例如KNX/EIB 家庭自动化监控软件。除了C/C++之外,Marc 还喜欢C#,并

且会用PHP 创建网页。

2007 年4 月,他凭借Visual C++方面的专业技能,获得了微软年度MVP 称号。

Marc 还是比利时C++用户组(www.becpp.org)的创始人,是C++ Standard Library Quick Reference(Apress)一

书的作者,以及多家出版社出版的多本书籍的技术编辑,是CodeGuru 论坛上的活跃分子(id 为Marc G)。Marc

还在www.nuonsoft.com/blog/上维护了一个博客,他热爱旅游和烹饪。

电子资料

www.luweidong.cn

下一个