目 录
第I部分 专业的C++简介
第1章 C++和标准库速成 3
1.1 C++速成 3
1.1.1 小程序“Hello World” 4
1.1.2 命名空间 8
1.1.3 字面量 10
1.1.4 变量 11
1.1.5 运算符 15
1.1.6 枚举 17
1.1.7 结构体 19
1.1.8 条件语句 20
1.1.9 条件运算符 22
1.1.10 逻辑比较运算符 23
1.1.11 三向比较运算符 24
1.1.12 函数 25
1.1.13 属性 27
1.1.14 C风格的数组 30
1.1.15 std::array 31
1.1.16 std::vector 32
1.1.17 std::pair 32
1.1.18 std::optional 33
1.1.19 结构化绑定 34
1.1.20 循环 34
1.1.21 初始化列表 36
1.1.22 C++中的字符串 36
1.1.23 作为面向对象语言的C++ 36
1.1.24 作用域解析 40
1.1.25 统一初始化 41
1.1.26 指针和动态内存 44
1.1.27 const的用法 47
1.1.28 引用 50
1.1.29 const_cast() 58
1.1.30 异常 59
1.1.31 类型别名 60
1.1.32 类型定义 61
1.1.33 类型推断 61
1.1.34 标准库 64
1.2 第一个大型的C++程序 64
1.2.1 雇员记录系统 64
1.2.2 Employee类 64
1.2.3 Database类 68
1.2.4 用户界面 70
1.2.5 评估程序 72
1.3 本章小结 73
1.4 练习 73
第2章 使用字符串和字符串视图 74
2.1 动态字符串 74
2.1.1 C风格字符串 74
2.1.2 字符串字面量 76
2.1.3 C++ std::string类 78
2.1.4 数值转换 82
2.1.5 std::string_view类 85
2.1.6 非标准字符串 87
2.2 字符串格式化与打印 87
2.2.1 格式字符串 88
2.2.2 参数索引 89
2.2.3 打印到不同的目的地 89
2.2.4 格式字符串的编译期验证 90
2.2.5 格式说明符 91
2.2.6 格式化转义字符和字符串 94
2.2.7 格式化范围 94
2.2.8 支持自定义类型 96
2.3 本章小结 99
2.4 练习 99
第3章 编码风格 101
3.1 良好外观的重要性 101
3.1.1 事先考虑 101
3.1.2 良好风格的元素 102
3.2 为代码编写文档 102
3.2.1 使用注释的原因 102
3.2.2 注释的风格 106
3.3 分解 109
3.3.1 通过重构分解 110
3.3.2 通过设计分解 111
3.3.3 本书中的分解 111
3.4 命名 111
3.4.1 选择恰当的名称 111
3.4.2 命名约定 112
3.5 使用具有风格的语言特性 113
3.5.1 使用常量 114
3.5.2 使用引用代替指针 114
3.5.3 使用自定义异常 115
3.6 格式 115
3.6.1 关于大括号对齐的争论 115
3.6.2 关于空格和圆括号的争论 116
3.6.3 空格、制表符、换行符 117
3.7 风格的挑战 117
3.8 本章小结 117
3.9 练习 118
第II部分 专业的C++软件设计
第4章 设计专业的C++程序 123
4.1 程序设计概述 123
4.2 程序设计的重要性 124
4.3 C++设计 126
4.4 C++设计的两个原则 126
4.4.1 抽象 126
4.4.2 重用 128
4.5 重用现有代码 130
4.5.1 关于术语的说明 130
4.5.2 决定是否重用代码 130
4.5.3 重用代码的指导原则 132
4.6 设计一个国际象棋程序 137
4.6.1 需求 137
4.6.2 设计步骤 138
4.7 本章小结 143
4.8 练习 143
第5章 面向对象设计 145
5.1 过程化的思考方式 145
5.2 面向对象思想 146
5.2.1 类 146
5.2.2 组件 146
5.2.3 属性 147
5.2.4 行为 147
5.2.5 综合考虑 147
5.3 生活在类的世界里 148
5.3.1 过度使用类 148
5.3.2 过于通用的类 149
5.4 类之间的关系 150
5.4.1 “有一个”关系 150
5.4.2 “是一个”关系(继承) 150
5.4.3 “有一个”与“是一个”的区别 152
5.4.4 not-a关系 155
5.4.5 层次结构 155
5.4.6 多重继承 156
5.4.7 混入类 157
5.5 本章小结 158
5.6 练习 158
第6章 设计可重用代码 160
6.1 重用哲学 160
6.2 如何设计可重用代码 161
6.2.1 使用抽象 161
6.2.2 构建理想的重用代码 162
6.2.3 设计有用的接口 168
6.2.4 设计成功的抽象 173
6.2.5 SOLID原则 174
6.3 本章小结 174
6.4 练习 175
第III部分 C++编码方法
第7章 内存管理 179
7.1 使用动态内存 180
7.1.1 如何描绘内存 180
7.1.2 分配和释放 181
7.1.3 数组 183
7.1.4 使用指针 189
7.2 数组-指针的对偶性 190
7.2.1 数组退化为指针 190
7.2.2 并非所有指针都是数组 192
7.3 底层内存操作 192
7.3.1 指针运算 192
7.3.2 自定义内存管理 193
7.3.3 垃圾回收 194
7.3.4 对象池 194
7.4 常见的内存陷阱 194
7.4.1 数据缓冲区分配不足以及内存访问越界 194
7.4.2 内存泄漏 196
7.4.3 双重释放和无效指针 198
7.5 智能指针 199
7.5.1 unique_ptr 199
7.5.2 shared_ptr 202
7.5.3 weak_ptr 205
7.5.4 向函数传递参数 206
7.5.5 从函数中返回 206
7.5.6 enable_shared_from_this 207
7.5.7 智能指针与C风格函数的交互 207
7.5.8 过时的、移除的auto_ptr 208
7.6 本章小结 208
7.7 练习 208
第8章 熟悉类和对象 210
8.1 电子表格示例介绍 210
8.2 编写类 211
8.2.1 类定义 211
8.2.2 定义方法 213
8.2.3 使用对象 215
8.2.4 this指针 217
8.2.5 显式对象参数 218
8.3 对象的生命周期 218
8.3.1 创建对象 218
8.3.2 销毁对象 233
8.3.3 对象赋值 234
8.3.4 编译器生成的拷贝构造函数和拷贝赋值运算符 237
8.3.5 复制和赋值的区别 237
8.4 本章小结 238
8.5 练习 239
第9章 精通类和对象 240
9.1 友元 240
9.2 对象中的动态内存分配 241
9.2.1 Spreadsheet类 241
9.2.2 使用析构函数释放内存 244
9.2.3 处理复制和赋值 245
9.2.4 使用移动语义处理移动 250
9.2.5 零规则 260
9.3 与成员函数有关的更多内容 261
9.3.1 static成员函数 261
9.3.2 const成员函数 262
9.3.3 成员函数重载 263
9.3.4 内联成员函数 267
9.3.5 默认参数 268
9.4 constexpr与consteval 269
9.4.1 constexpr关键字 269
9.4.2 consteval关键字 270
9.4.3 constexpr 和 consteval 类 271
9.5 不同的数据成员类型 272
9.5.1 静态数据成员 272
9.5.2 const static数据成员 274
9.5.3 引用数据成员 274
9.6 嵌套类 276
9.7 类内的枚举类型 277
9.8 运算符重载 277
9.8.1 示例:为SpreadsheetCell实现加法 278
9.8.2 重载算术运算符 281
9.8.3 重载比较运算符 282
9.9 创建稳定的接口 286
9.10 本章小结 289
9.11 练习 290
第10章 揭秘继承技术 291
10.1 使用继承构建类 291
10.1.1 扩展类 292
10.1.2 重写成员函数 295
10.2 使用继承重用代码 302
10.2.1 WeatherPrediction类 302
10.2.2 在派生类中添加功能 303
10.2.3 在派生类中替换功能 304
10.3 利用父类 305
10.3.1 父类构造函数 305
10.3.2 父类的析构函数 306
10.3.3 构造函数和析构函数中的虚成员函数调用 307
10.3.4 使用父类成员函数 308
10.3.5 向上转型和向下转型 310
10.4 继承与多态性 311
10.4.1 回到电子表格 311
10.4.2 设计多态性的电子表格单元格 311
10.4.3 SpreadsheetCell基类 312
10.4.4 独立的派生类 313
10.4.5 利用多态性 315
10.4.6 考虑将来 316
10.4.7 提供纯虚成员函数的实现 317
10.5 多重继承 318
10.5.1 从多个类继承 318
10.5.2 名称冲突和歧义基类 319
10.6 有趣而晦涩的继承问题 321
10.6.1 修改重写成员函数的返回类型 322
10.6.2 派生类中添加虚基类成员函数的重载 324
10.6.3 继承的构造函数 325
10.6.4 重写成员函数时的特殊情况 328
10.6.5 派生类中的拷贝构造函数和赋值运算符 334
10.6.6 运行时类型工具 335
10.6.7 非public继承 337
10.6.8 虚基类 337
10.7 类型转换 340
10.7.1 static_cast() 340
10.7.2 reinterpret_cast() 341
10.7.3 dynamic_cast() 342
10.7.4 std::bit_cast() 343
10.7.5 类型转换小结 343
10.8 本章小结 344
10.9 练习 344
第11章 模块、头文件和其他主题 345
11.1 模块 345
11.1.1 非模块化代码 346
11.1.2 标准命名模块 346
11.1.3 模块接口文件 347
11.1.4 模块实现文件 348
11.1.5 从实现中分离接口 349
11.1.6 可见性和可访问性 350
11.1.7 子模块 350
11.1.8 模块划分 351
11.1.9 私有模块片段 353
11.1.10 头文件单元 355
11.1.11 可导入的标准库头文件 355
11.2 预处理指令 357
11.3 链接 358
11.3.1 内部链接 359
11.3.2 extern 关键字 360
11.4 头文件 361
11.4.1 单一定义规则(ODR) 361
11.4.2 重复定义 361
11.4.3 循环依赖 362
11.4.4 查询头文件是否存在 363
11.4.5 模块导入声明 363
11.5 核心语言特性的特性测试宏 363
11.6 static关键字 364
11.6.1 静态数据成员和成员函数 364
11.6.2 函数中的静态变量 364
11.6.3 非局部变量的初始化顺序 365
11.6.4 非局部变量的销毁顺序 365
11.7 C 风格的可变长度参数列表 365
11.7.1 访问参数 366
11.7.2 为什么不应该使用C风格的变长参数列表 367
11.8 本章小结 367
11.9 练习 367
第12章 利用模板编写泛型代码 369
12.1 模板概述 370
12.2 类模板 370
12.2.1 编写类模板 370
12.2.2 编译器处理模板的原理 378
12.2.3 将模板代码分布到多个文件中 379
12.2.4 模板参数 380
12.2.5 成员函数模板 383
12.2.6 类模板的特化 389
12.2.7 从类模板派生 391
12.2.8 继承还是特化 392
12.2.9 模板别名 392
12.3 函数模板 393
12.3.1 函数重载与函数模板 394
12.3.2 函数模板的重载 394
12.3.3 类模板的友元函数模板 395
12.3.4 对模板参数推导的更多介绍 397
12.3.5 函数模板的返回类型 397
12.3.6 简化函数模板的语法 399
12.4 变量模板 399
12.5 概念 400
12.5.1 语法 400
12.5.2 约束表达式 401
12.5.3 预定义的标准概念 403
12.5.4 类型约束的auto 404
12.5.5 类型约束和函数模板 404
12.5.6 类型约束和类模板 407
12.5.7 类型约束和类成员函数 407
12.5.8 基于约束的类模板特化和函数模板重载 408
12.5.9 最佳实践 408
12.6 本章小结 409
12.7 练习 409
第13章 C++ I/O揭秘 410
13.1 使用流 411
13.1.1 流的含义 411
13.1.2 流的来源和目的地 412
13.1.3 流式输出 412
13.1.4 流式输入 417
13.1.5 对象的输入输出 423
13.1.6 自定义的操作算子 424
13.2 字符串流 425
13.3 基于span的流 426
13.4 文件流 427
13.4.1 文本模式与二进制模式 428
13.4.2 通过seek()和tell()在文件中转移 428
13.4.3 将流链接在一起 430
13.4.4 读取整个文件 431
13.5 双向I/O 431
13.6 文件系统支持库 432
13.6.1 路径 432
13.6.2 目录条目 434
13.6.3 辅助函数 434
13.6.4 目录遍历 434
13.7 本章小结 435
13.8 练习 436
第14章 错误处理 437
14.1 错误与异常 437
14.1.1 异常的含义 438
14.1.2 C++中异常的优点 438
14.1.3 建议 439
14.2 异常机制 439
14.2.1 抛出和捕获异常 440
14.2.2 异常类型 442
14.2.3 按const引用捕获异常对象 443
14.2.4 抛出并捕获多个异常 443
14.2.5 未捕获的异常 446
14.2.6 noexcept说明符 447
14.2.7 noexcept(expression)说明符 448
14.2.8 noexcept(expression)运算符 448
14.2.9 抛出列表 448
14.3 异常与多态性 449
14.3.1 标准异常层次结构 449
14.3.2 在类层次结构中捕获异常 450
14.3.3 编写自己的异常类 451
14.3.4 嵌套异常 453
14.4 重新抛出异常 455
14.5 栈的释放与清理 456
14.5.1 使用智能指针 458
14.5.2 捕获、清理并重新抛出 458
14.6 源码位置 459
14.6.1 日志记录的源码位置 459
14.6.2 在自定义异常中自动嵌入源位置 460
14.7 堆栈跟踪 461
14.7.1 堆栈跟踪库 461
14.7.2 在自定义异常中自动嵌入堆栈跟踪 462
14.8 常见的错误处理问题 464
14.8.1 内存分配错误 464
14.8.2 构造函数中的错误 466
14.8.3 构造函数的function-try-blocks 468
14.8.4 析构函数中的错误 470
14.9 异常安全保证 471
14.10 本章小结 471
14.11 练习 471
第15章 C++运算符重载 473
15.1 运算符重载概述 473
15.1.1 重载运算符的原因 474
15.1.2 运算符重载的限制 474
15.1.3 运算符重载的选择 474
15.1.4 不应重载的运算符 476
15.1.5 可重载运算符小结 476
15.1.6 右值引用 479
15.1.7 优先级和结合性 480
15.1.8 关系运算符 481
15.1.9 替代符号 481
15.2 重载算术运算符 482
15.2.1 重载一元负号和一元正号运算符 482
15.2.2 重载递增和递减运算符 482
15.3 重载按位运算符和二元逻辑运算符 483
15.4 重载插入运算符和提取运算符 483
15.5 重载下标运算符 485
15.5.1 通过operator[]提供只读访问 488
15.5.2 多维下标运算符 489
15.5.3 非整数数组索引 490
15.5.4 静态下标运算符 490
15.6 重载函数调用运算符 491
15.7 重载解除引用运算符 492
15.7.1 实现operator* 494
15.7.2 实现operator-> 494
15.7.3 operator.*和operator ->*的含义 494
15.8 编写转换运算符 495
15.8.1 auto运算符 496
15.8.2 使用显式转换运算符解决多义性问题 496
15.8.3 用于布尔表达式的转换 497
15.9 重载内存分配和内存释放运算符 498
15.9.1 new和delete的工作原理 499
15.9.2 重载operator new和operator delete 500
15.9.3 显式地删除/默认化operator new和operator delete 502
15.9.4 重载带有额外参数的operator new和operator delete 502
15.9.5 重载带有内存大小参数的operator delete 503
15.10 重载用户定义的字面量运算符 504
15.10.1 标准库定义的字面量 504
15.10.2 用户自定义的字面量 504
15.11 本章小结 506
15.12 练习 506
第16章 C++标准库概述 508
16.1 编码原则 509
16.1.1 使用模板 509
16.1.2 使用运算符重载 509
16.2 C++标准库概述 509
16.2.1 字符串 509
16.2.2 正则表达式 510
16.2.3 I/O流 510
16.2.4 智能指针 510
16.2.5 异常 510
16.2.6 标准整数类型 511
16.2.7 数学工具 511
16.2.8 整数比较 512
16.2.9 位操作 512
16.2.10 时间和日期工具 513
16.2.11 随机数 513
16.2.12 初始化列表 513
16.2.13 Pair和Tuple 513
16.2.14 词汇类型 513
16.2.15 函数对象 514
16.2.16 文件系统 514
16.2.17 多线程 514
16.2.18 类型萃取 514
16.2.19 标准库特性测试宏 514
16.2.20 <version> 515
16.2.21 源位置 516
16.2.22 堆栈跟踪 516
16.2.23 容器 516
16.2.24 算法 522
16.2.25 范围库 529
16.2.26 标准库中还缺什么 530
16.3 本章小结 530
16.4 练习 530
第17章 理解迭代器与范围库 532
17.1 迭代器 532
17.1.1 获取容器的迭代器 534
17.1.2 迭代器萃取 536
17.1.3 示例 536
17.1.4 使用迭代器特性进行函数分发 537
17.2 流迭代器 539
17.2.1 输出流迭代器:ostream_iterator 539
17.2.2 输入流迭代器:istream_iterator 540
17.2.3 输入流迭代器:istreambuf_iterator 540
17.3 迭代器适配器 540
17.3.1 插入迭代器 541
17.3.2 逆向迭代器 542
17.3.3 移动迭代器 543
17.4 范围 544
17.4.1 约束算法 545
17.4.2 视图 547
17.4.3 范围工厂 552
17.4.4 将范围转换为容器 554
17.5 本章小结 555
17.6 练习 556
第18章 标准库容器 557
18.1 容器概述 557
18.1.1 对元素的要求 558
18.1.2 异常和错误检查 559
18.2 顺序容器 559
18.2.1 vector 560
18.2.2 vector<bool>特化 578
18.2.3 deque 578
18.2.4 list 579
18.2.5 forward_list 581
18.2.6 array 584
18.3 顺序视图 585
18.3.1 span 585
18.3.2 mdspan 587
18.4 容器适配器 588
18.4.1 queue 588
18.4.2 priority_queue 591
18.4.3 stack 593
18.5 关联容器 593
18.5.1 有序关联容器 594
18.5.2 无序关联容器/哈希表 607
18.5.3 平坦集合和平坦映射关联容器适配器 613
18.5.4 关联容器的性能 614
18.6 其他容器 614
18.6.1 标准C风格数组 614
18.6.2 string 615
18.6.3 流 615
18.6.4 bitset 616
18.7 本章小结 620
18.8 练习 620
第19章 函数指针、函数对象、lambda表达式 622
19.1 函数指针 622
19.1.1 findMatches() 使用函数指针 623
19.1.2 findMatches() 函数模板 624
19.1.3 Windows DLL和函数指针 625
19.2 指向成员函数(和数据成员)的指针 626
19.3 函数对象 627
19.3.1 编写第一个函数对象 627
19.3.2 标准库中的函数对象 627
19.4 多态功能包装器 634
19.4.1 std::function 634
19.4.2 std::move_only_function 635
19.5 lambda表达式 636
19.5.1 语法 636
19.5.2 lambda表达式作为参数 640
19.5.3 泛型lambda表达式 641
19.5.4 lambda捕获表达式 641
19.5.5 模板化lambda表达式 642
19.5.6 lambda 表达式作为返回类型 643
19.5.7 未计算上下文中的lambda表达式 643
19.5.8 默认构造、拷贝和赋值 643
19.5.9 递归lambda表达式 644
19.6 调用 644
19.7 本章小结 645
19.8 练习 645
第20章 掌握标准库算法 647
20.1 算法概述 647
20.1.1 find() 和 find_if() 算法 648
20.1.2 accumulate() 算法 650
20.1.3 在算法中使用移动语义 651
20.1.4 算法回调 651
20.2 算法详解 652
20.2.1 非修改序列算法 652
20.2.2 修改序列算法 657
20.2.3 操作算法 665
20.2.4 分区算法 667
20.2.5 排序算法 668
20.2.6 二分查找算法 669
20.2.7 集合算法 670
20.2.8 最小/最大算法 672
20.2.9 并行算法 673
20.2.10 数值处理算法 674
20.2.11 约束算法 676
20.3 本章小结 678
20.4 练习 678
第21章 字符串的本地化与正则表达式 680
21.1 本地化 680
21.1.1 宽字符 680
21.1.2 非西方字符集 681
21.1.3 本地化字符串字面量 683
21.1.4 locale和facet 683
21.2 正则表达式 688
21.2.1 ECMAScript语法 689
21.2.2 regex库 693
21.2.3 regex_match() 694
21.2.4 regex_search() 696
21.2.5 regex_iterator 697
21.2.6 regex_token_iterator 698
21.2.7 regex_replace() 700
21.3 本章小结 702
21.4 练习 702
第22章 日期和时间工具 704
22.1 编译期有理数 704
22.2 持续时间 706
22.2.1 示例与duration转换 707
22.2.2 预定义的duration 709
22.2.3 标准字面量 710
22.2.4 hh_mm_ss 710
22.3 时钟 710
22.3.1 打印当前时间 711
22.3.2 执行时间 712
22.4 时间点 712
22.5 日期 714
22.5.1 创建日期 714
22.5.2 打印日期 716
22.5.3 日期运算 717
22.6 时区 717
22.7 本章小结 718
22.8 练习 719
第23章 随机数工具 720
23.1 C风格随机数生成器 720
23.2 随机数引擎 721
23.3 随机数引擎适配器 722
23.4 预定义的随机数引擎和引擎适配器 723
23.5 生成随机数 723
23.6 随机数分布 725
23.7 本章小结 728
23.8 练习 728
第24章 其他词汇类型 729
24.1 variant 729
24.2 any 731
24.3 元组 732
24.3.1 分解元组 734
24.3.2 串联 735
24.3.3 比较 736
24.3.4 make_from_tuple() 737
24.3.5 apply() 737
24.4 optional:单子式操作 737
24.5 expected 738
24.6 本章小结 741
24.7 练习 741
第IV部分 掌握C++的高级特性
第25章 自定义和扩展标准库 745
25.1 分配器 745
25.2 扩展标准库 746
25.2.1 扩展标准库的原因 747
25.2.2 编写标准库算法 747
25.2.3 编写标准库容器 749
25.3 本章小结 773
25.4 练习 774
第26章 高级模板 775
26.1 深入了解模板参数 775
26.1.1 深入了解模板类型参数 775
26.1.2 template template参数介绍 778
26.1.3 深入了解非类型模板参数 780
26.2 类模板部分特化 781
26.3 通过重载模拟函数部分特化 784
26.4 模板递归 785
26.4.1 N维网格:初次尝试 786
26.4.2 真正的N维网格 786
26.5 变参模板 788
26.5.1 类型安全的变长参数列表 788
26.5.2 可变数目的混入类 791
26.5.3 折叠表达式 792
26.6 模板元编程 794
26.6.1 编译期阶乘 794
26.6.2 循环展开 795
26.6.3 打印元组 795
26.6.4 类型萃取 798
26.6.5 模板元编程总结 809
26.7 本章小结 809
26.8 练习 809
第27章 C++多线程编程 810
27.1 多线程编程概述 811
27.1.1 争用条件 812
27.1.2 撕裂 813
27.1.3 死锁 813
27.1.4 伪共享 814
27.2 线程 815
27.2.1 通过函数指针创建线程 815
27.2.2 通过函数对象创建线程 816
27.2.3 通过lambda创建线程 817
27.2.4 通过成员函数指针创建线程 818
27.2.5 线程本地存储 818
27.2.6 取消线程 819
27.2.7 自动join线程 819
27.2.8 从线程获得结果 820
27.2.9 复制和重新抛出异常 821
27.3 原子操作库 823
27.3.1 原子操作 825
27.3.2 原子智能指针 826
27.3.3 原子引用 826
27.3.4 使用原子类型 826
27.3.5 等待原子变量 828
27.4 互斥 829
27.4.1 互斥量类 829
27.4.2 锁 831
27.4.3 std::call_once 834
27.4.4 互斥量的用法示例 835
27.5 条件变量 838
27.5.1 虚假唤醒 839
27.5.2 使用条件变量 839
27.6 latch 840
27.7 barrier 841
27.8 semaphore 843
27.9 future 843
27.9.1 std::promise和std::future 844
27.9.2 std::packaged_task 845
27.9.3 std::async 845
27.9.4 异常处理 846
27.9.5 std::shared_future 847
27.10 示例:多线程的Logger类 848
27.11 线程池 852
27.12 协程 852
27.13 线程设计和最佳实践 854
27.14 本章小结 855
27.15 练习 855
第V部分 C++软件工程
第28章 充分利用软件工程方法 859
28.1 过程的必要性 859
28.2 软件生命周期模型 860
28.2.1 瀑布模型 860
28.2.2 生鱼片模型 862
28.2.3 螺旋类模型 862
28.2.4 敏捷 864
28.3 软件工程方法论 865
28.3.1 Scrum 865
28.3.2 UP 867
28.3.3 RUP 868
28.3.4 极限编程 869
28.3.5 软件分流 872
28.4 构建自己的过程和方法 873
28.4.1 对新思想采取开放态度 873
28.4.2 提出新想法 873
28.4.3 知道什么行得通、什么行不通 873
28.4.4 不要逃避 873
28.5 版本控制 873
28.6 本章小结 875
28.7 练习 875
第29章 编写高效的C++程序 876
29.1 性能和效率概述 876
29.1.1 提升效率的两种方式 877
29.1.2 两种程序 877
29.1.3 C++是不是低效的语言 877
29.2 语言层次的效率 877
29.2.1 高效地操纵对象 878
29.2.2 预分配内存 881
29.2.3 使用内联函数 881
29.2.4 标记无法访问的代码 881
29.3 设计层次的效率 882
29.3.1 尽可能多地缓存 882
29.3.2 使用对象池 883
29.4 剖析 888
29.4.1 使用gprof的剖析示例 888
29.4.2 使用Visual C++ 2022的剖析示例 895
29.5 本章小结 897
29.6 练习 897
第30章 熟练掌握测试技术 898
30.1 质量控制 899
30.1.1 谁负责测试 899
30.1.2 bug的生命周期 899
30.1.3 bug跟踪工具 900
30.2 单元测试 901
30.2.1 单元测试方法 902
30.2.2 单元测试过程 902
30.2.3 实际中的单元测试 905
30.3 模糊测试 912
30.4 高级测试 913
30.4.1 集成测试 913
30.4.2 系统测试 914
30.4.3 回归测试 914
30.5 用于成功测试的建议 915
30.6 本章小结 915
30.7 练习 916
第31章 熟练掌握调试技术 917
31.1 调试的基本定律 917
31.2 bug分类学 918
31.3 避免bug 918
31.4 为bug做好规划 919
31.4.1 错误日志 919
31.4.2 调试跟踪 920
31.4.3 断言 927
31.4.4 崩溃转储 928
31.5 调试技术 928
31.5.1 重现bug 928
31.5.2 调试可重复的bug 929
31.5.3 调试不可重现的bug 929
31.5.4 调试退化 930
31.5.5 调试内存问题 930
31.5.6 调试多线程程序 934
31.5.7 调试示例:文章引用 934
31.5.8 从ArticleCitations示例中总结出的教训 945
31.6 本章小结 946
31.7 练习 946
第32章 使用设计技术和框架 948
32.1 容易忘记的语法 949
32.1.1 编写类 949
32.1.2 派生类 950
32.1.3 编写lambda表达式 951
32.1.4 使用“复制和交换”惯用语法 951
32.1.5 抛出和捕获异常 952
32.1.6 写入类模板 953
32.1.7 约束模板参数 953
32.1.8 写入文件 954
32.1.9 读取文件 954
32.2 始终存在更好的方法 955
32.2.1 RAII 955
32.2.2 双分派 958
32.2.3 混入类 961
32.3 面向对象的框架 965
32.3.1 使用框架 965
32.3.2 MVC范型 966
32.4 本章小结 967
32.5 练习 967
第33章 应用设计模式 968
33.1 策略模式 969
33.1.1 示例:日志机制 969
33.1.2 基于策略logger的实现 969
33.1.3 使用基于策略的Logger 970
33.2 抽象工厂模式 971
33.2.1 示例:模拟汽车工厂 971
33.2.2 实现抽象工厂 972
33.2.3 使用抽象工厂 973
33.3 工厂方法模式 974
33.3.1 示例:模拟第二个汽车工厂 974
33.3.2 实现工厂的方法 975
33.3.3 使用工厂方法 976
33.3.4 其他用法 978
33.4 其他工厂模式 978
33.5 适配器模式 979
33.5.1 示例:适配Logger类 979
33.5.2 实现适配器 980
33.5.3 使用适配器 981
33.6 代理模式 981
33.6.1 示例:隐藏网络连接问题 981
33.6.2 实现代理 981
33.6.3 使用代理 982
33.7 迭代器模式 983
33.8 观察者模式 983
33.8.1 示例:从主题中暴露事件 983
33.8.2 实现观察者 984
33.8.3 使用观察者 985
33.9 装饰器模式 986
33.9.1 示例:在网页中定义样式 986
33.9.2 装饰器的实现 987
33.9.3 使用装饰器 988
33.10 责任链模式 988
33.10.1 示例:事件处理 989
33.10.2 实现责任链 989
33.10.3 使用责任链 990
33.11 单例模式 991
33.11.1 日志记录机制 992
33.11.2 实现单例 992
33.11.3 使用单例 994
33.12 本章小结 994
33.13 练习 994
第34章 开发跨平台和跨语言的应用程序 996
34.1 跨平台开发 996
34.1.1 架构问题 997
34.1.2 实现问题 999
34.1.3 平台专用功能 1001
34.2 跨语言开发 1002
34.2.1 混用C和C++ 1002
34.2.2 改变范型 1002
34.2.3 链接C代码 1005
34.2.4 从C#调用C++代码 1006
34.2.5 在C++中使用C#代码及在C#中使用C++代码 1008
34.2.6 在Java中使02用JNI调用C++代码 1009
34.2.7 从C++代码调用脚本 1011
34.2.8 从脚本调用C++代码 1011
34.2.9 从C++调用汇编代码 1013
34.3 本章小结 1014
34.4 练习 1014
——以下内容可扫封底二维码下载——
第VI部分 附录
附录A C++面试 1019
附录B 参考文献及相关介绍 1039
附录C 标准库头文件 1048
附录D UML简介 1054