在科学和工程领域,很多软件都是用C++来实现的。随着软件项目的规模越来越大,C++的优势更加突出。C++既能够支持足够贴近硬件层面的编程工作,又能够驾驭高级抽象的编程需求。因此,全面掌握C++语言的语法及新特性,对开发者非常重要。
本书由浅入深地介绍了C++编程的方方面面,涉及C++基础、类、泛型编程、程序库、元编程、面向对象编程、科学项目等内容,还通过3个附录(程序库、编程工具、语言规范)全面介绍了一些拓展知识。
本书适合想全面学习C++编程的读者以及对C++新特性感兴趣的读者阅读参考。
本书是你掌握 C++ 编程精髓的得力助手。无论你是硬件底层的编程高手,还是追求高级抽象思维的软件工程师,本书都将引领你深入C++的每一个层面。
本书紧跟 C++17 和 C++20 的新标准,通过丰富多样的技术案例,为你呈现 C++ 编程的强大魅力。
本书由资深C++教育专家彼得·哥特史林(Peter Gottschling)编写,结合其在物理、数学、工程领域的教学经验,为你细致解读C++的高级特性,带你领略从基础到高级的编程艺术。
无论你的编程经验如何,你都将快速掌握 lambda 表达式、可变参数模板等日益强大的C++特性。
彼得·哥特史林(Peter Gottschling)专注于开发行业领先的科学计算软件,是 ISO C++ 标准委员会成员,德国编程语言标准委员会主席,以及德累斯顿 C++ 用户组的创始人。曾就读于德累斯顿工业大学,并同时学习了数学和计算机科学两门专业,分别获得学士学位和博士学位。
第 1章 C++基础 1
1.1 我们的第 一个程序 1
1.2 变量 3
1.2.1 内置类型 4
1.2.2 字符和字符串 5
1.2.3 声明变量 6
1.2.4 常量 6
1.2.5 字面量 7
1.2.6 非窄化初始化 9
1.2.7 作用域 10
1.3 操作符 12
1.3.1 算术操作符 13
1.3.2 布尔操作符 15
1.3.3 位操作符 17
1.3.4 赋值操作符 17
1.3.5 程序控制流 18
1.3.6 内存管理 19
1.3.7 访问操作符 19
1.3.8 类型处理 19
1.3.9 异常处理 20
1.3.10 操作符重载 20
1.3.11 操作符优先级 20
1.3.12 避免歧义 21
1.4 表达式和语句 23
1.4.1 表达式 23
1.4.2 语句 24
1.4.3 分支 24
1.4.4 循环 27
1.4.5 goto 30
1.5 函数 30
1.5.1 参数 30
1.5.2 返回值 32
1.5.3 内联 33
1.5.4 重载 34
1.5.5 main函数 35
1.6 异常处理 36
1.6.1 断言 36
1.6.2 异常 38
1.6.3 静态断言 42
1.7 I/O 42
1.7.1 标准输出 42
1.7.2 标准输入 43
1.7.3 文件的输入和输出 43
1.7.4 通用流的概念 44
1.7.5 格式化 45
1.7.6 新型格式化 46
1.7.7 处理I/O异常 49
1.7.8 文件系统 52
1.8 数组、指针和引用 53
1.8.1 数组 53
1.8.2 指针 55
1.8.3 智能指针 57
1.8.4 引用 60
1.8.5 指针和引用的区别 61
1.8.6 不要引用过期数据 61
1.8.7 数组的容器 62
1.9 结构化的软件项目 64
1.9.1 注释 65
1.9.2 预处理器指令 66
1.10 练习 70
1.10.1 窄化 70
1.10.2 字面量 70
1.10.3 操作符 70
1.10.4 分支 71
1.10.5 循环 71
1.10.6 I/O 71
1.10.7 数组和指针 71
1.10.8 函数 71
第 2章 类 72
2.1 为通用性编程而不局限于技术细节 72
2.2 成员 74
2.2.1 成员变量 74
2.2.2 可访问性 75
2.2.3 访问操作符 77
2.2.4 类的静态声明 77
2.2.5 成员函数 78
2.3 设置值:构造函数与赋值 79
2.3.1 构造函数 79
2.3.2 赋值 88
2.3.3 初始化器列表 89
2.3.4 统一初始化 91
2.3.5 移动语义 93
2.3.6 通过字面量构造对象 102
2.4 析构函数 104
2.4.1 实现规则 104
2.4.2 妥善处理资源 104
2.5 方法生成总结 110
2.6 访问成员变量 111
2.6.1 访问函数 111
2.6.2 下标操作符 112
2.6.3 常量成员函数 113
2.6.4 引用限定的成员 114
2.7 操作符重载的设计 116
2.7.1 保持一致性 116
2.7.2 优先级 117
2.7.3 成员函数和自由函数 117
2.7.4 重载等式 119
2.7.5 重载“飞船”运算符 121
2.7.6 重载中的类型系统 123
2.8 练习 124
2.8.1 多项式 124
2.8.2 有理数 124
2.8.3 移动赋值 125
2.8.4 初始化器列表 125
2.8.5 资源管理 125
第3章 泛型编程 126
3.1 函数模板 126
3.1.1 实例化 127
3.1.2 参数类型推导 128
3.1.3 处理模板中的异常 132
3.1.4 混合类型 133
3.1.5 统一初始化 134
3.1.6 自动返回的类型 134
3.1.7 模板参数简化 135
3.2 命名空间和函数查找 135
3.2.1 命名空间 135
3.2.2 参数依赖查找 138
3.2.3 命名空间限定和ADL 142
3.3 类模板 144
3.3.1 容器示例 144
3.3.2 设计统一的类和函数接口 146
3.4 类型推导和定义 151
3.4.1 自动变量类型 152
3.4.2 表达式的类型 152
3.4.3 decltype(auto) 153
3.4.4 类模板参数推导 154
3.4.5 推导多种类型 156
3.4.6 定义类型 157
3.5 模板特例化 159
3.5.1 为某种类型特例化一个类 159
3.5.2 函数特例化和重载 162
3.5.3 类的偏特化 163
3.5.4 偏特化函数 164
3.5.5 用户自定义类型的结构化绑定 166
3.5.6 用户自定义格式化 169
3.6 模板的非类型参数 171
3.6.1 固定大小的容器 171
3.6.2 推导非类型参数 173
3.7 函子 174
3.7.1 类函数参数 176
3.7.2 组合函子 177
3.7.3 递归 178
3.7.4 泛型规约 181
3.8 lambda表达式 182
3.8.1 捕获 183
3.8.2 泛型lambda 186
3.9 变量模板 188
3.10 概念编程 190
3.10.1 定义概念 191
3.10.2 通过概念分发 194
3.10.3 类中的概念 195
3.10.4 概念设计 197
3.11 可变参数模板 197
3.11.1 递归函数 197
3.11.2 直接展开 199
3.11.3 索引序列 200
3.11.4 折叠表达式 202
3.11.5 类型生成器 202
3.11.6 增长测试 203
3.12 练习 205
3.12.1 字符串表达 205
3.12.2 元组的字符串表达 205
3.12.3 泛型堆栈 205
3.12.4 带类型参数的有理数 205
3.12.5 向量的迭代器 206
3.12.6 奇数迭代器 206
3.12.7 奇数范围 206
3.12.8 bool堆栈 206
3.12.9 自定义大小的堆栈 206
3.12.10 梯形法则 207
3.12.11 带静态函数的部分特例化 207
3.12.12 Functor函子 207
3.12.13 Lambda 207
3.12.14 实现 make_unique 207
第4章 程序库 208
4.1 标准模板库 208
4.1.1 入门示例 209
4.1.2 迭代器 209
4.1.3 容器 214
4.1.4 算法 223
4.1.5 范围(Range) 228
4.1.6 并行计算 234
4.2 数值计算 236
4.2.1 复数 236
4.2.2 随机数生成器 239
4.2.3 数学专用函数 247
4.2.4 数学常量 248
4.3 元编程 249
4.3.1 极限(limits) 250
4.3.2 类型特征 251
4.4 实用程序 253
4.4.1 optional 253
4.4.2 元组(tuple) 254
4.4.3 variant 256
4.4.4 any 258
4.4.5 string_view 259
4.4.6 span 260
4.4.7 function 261
4.4.8 引用包装器 263
4.5 关于时间 264
4.6 并发编程 267
4.6.1 专用术语 267
4.6.2 概述 267
4.6.3 thread 268
4.6.4 关于调用者 269
4.6.5 异步调用 271
4.6.6 异步解析器 272
4.6.7 可变互斥锁 277
4.6.8 协程 278
4.6.9 其他新的并发特性 280
4.7 高级科学软件库 280
4.7.1 替代算法 280
4.7.2 区间运算 281
4.7.3 线性代数 281
4.7.4 常微分方程 281
4.7.5 偏微分方程 282
4.7.6 图形算法 282
4.8 练习 282
4.8.1 根据大小排序 282
4.8.2 将lambda表达式作为谓词进行
查找 282
4.8.3 STL 容器 283
4.8.4 复数 283
4.8.5 并行的向量加法 284
4.8.6 重构并行加法 284
第5章 元编程 285
5.1 让编译器计算 285
5.1.1 编译期函数 285
5.1.2 扩展编译期函数 287
5.1.3 素数 289
5.1.4 常量的恒定性 291
5.1.5 编译期lambda表达式 292
5.2 提供和使用类型信息 293
5.2.1 类型特征 294
5.2.2 条件异常处理 297
5.2.3 const简洁视图用例 298
5.2.4 参数化有理数 304
5.2.5 特定领域的类型属性 306
5.2.6 enable_if 307
5.2.7 可变参数模板的优化 311
5.3 表达式模板 314
5.3.1 简单的操作符 314
5.3.2 表达式模板类 317
5.3.3 泛型表达式模板 320
5.3.4 在数据过期之前复制 321
5.4 元调优:编写自定义编译器优化 323
5.4.1 经典的固定尺寸展开 325
5.4.2 嵌套展开 327
5.4.3 动态展开 332
5.4.4 展开向量表达式 334
5.4.5 优化表达式模板 335
5.4.6 调优简化操作 338
5.4.7 嵌套循环调优 345
5.4.8 调优小结 348
5.5 语义概念优化 349
5.5.1 语义调优的需求 350
5.5.2 语义概念层次 353
5.6 图灵完备性 355
5.7 练习 357
5.7.1 类型特征 357
5.7.2 斐波那契数列 357
5.7.3 最大公约数元程序 358
5.7.4 混合类型的有理数 358
5.7.5 向量表达式模板 358
5.7.6 元列表 359
第6章 面向对象编程 360
6.1 基本原则 360
6.1.1 基类和派生类 361
6.1.2 继承构造函数 364
6.1.3 虚函数和多态类 365
6.1.4 通过继承实现函子 371
6.1.5 派生Exception类 372
6.2 去除冗余 374
6.3 多重继承 375
6.3.1 多个父类 375
6.3.2 普通的“祖父母” 376
6.4 子类型的动态选择 381
6.5 转型 384
6.5.1 基类和派生类之间的转换 384
6.5.2 常量转型 388
6.5.3 重新解析的转型 388
6.5.4 函数式转型 388
6.5.5 隐式转换 390
6.6 高级技术 391
6.6.1 CRTP 391
6.6.2 包含重载的类型特征 395
6.7 练习 399
6.7.1 非冗余菱形 399
6.7.2 继承向量类 399
6.7.3 重构向量中的异常 399
6.7.4 抛出异常测试 399
6.7.5 Clone 函数 400
第7章 科学项目 401
7.1 ODE解析器的实现 401
7.1.1 常微分方程 401
7.1.2 Runge-Kutta算法 403
7.1.3 泛型实现 404
7.1.4 展望 411
7.2 创建项目 412
7.2.1 构建过程 412
7.2.2 构建工具 416
7.2.3 单独编译 420
7.3 模块 423
7.4 结语 427
附录A 程序库 428
A.1 科学软件的优劣 428
A.2 基本的细节 434
A.2.1 静态变量 434
A.2.2 关于if语句 435
A.2.3 达夫设备 436
A.2.4 程序调用 436
A.2.5 断言和异常 437
A.2.6 二进制I/O 438
A.2.7 C风格的 I/O 439
A.2.8 垃圾回收机制 440
A.2.9 宏的问题 440
A.3 实际用例:矩阵转置 442
A.4 类的详细信息 451
A.4.1 指向成员的指针 451
A.4.2 更多初始化示例 451
A.4.3 访问多维数据结构 452
A.5 方法生成 455
A.5.1 自动生成 455
A.5.2 控制生成 458
A.5.3 生成规则 458
A.5.4 设计指南和不足 462
A.6 模板 465
A.6.1 统一初始化 465
A.6.2 函数调用 466
A.6.3 为特定硬件特例化 469
A.6.4 可变参数二进制I/O 470
A.7 关于软件库的更多信息 471
A.7.1 在C++03中使用std::vector 471
A.7.2 可变参数 471
A.8 旧式的动态选择 472
A.9 元编程 473
A.9.1 历史上的第 一个元编程 473
A.9.2 元函数 475
A.9.3 向后兼容的静态断言 477
A.9.4 匿名类型参数 477
A.10 链接到C代码 480
附录B 编程工具 483
B.1 g++ 483
B.2 调试 484
B.2.1 基于文本的调试器 484
B.2.2 图形化界面调试工具:DDD 486
B.3 内存分析 488
B.4 gnuplot 489
B.5 UNIX、Linux和macOS 490
附录C 语言规范 492
C.1 值类别 492
C.2 操作符概要 493
C.3 转换规则 496
C.3.1 提升 496
C.3.2 其他转换 496
C.3.3 常用的算术转换 497
C.3.4 窄化 498
参考资料 499