第1章 对象导言 1
1.1 抽象的过程 1
1.2 对象有一个接口 2
1.3 实现的隐藏 4
1.4 实现的重用 5
1.5 继承:重用接口 5
1.5.1 is-a关系和is-like-a关系 8
1.6 具有多态性的可互换对象 8
1.7 创建和销毁对象 11
1.8 异常处理:应对错误 12
1.9 分析和设计 12
1.9.1 第0阶段:制定计划 14
1.9.1.1 任务陈述 14
1.9.2 第1阶段:我们在做什么 14
1.9.3 第2阶段:我们将如何建立对象 16
1.9.3.1 对象设计的五个阶段 17
1.9.3.2 对象开发准则 18
1.9.4 第3阶段:创建核心 18
1.9.5 第4阶段:迭代用例 19
1.9.6 第5阶段:进化 19
1.9.7 计划的回报 20
1.10 极限编程 20
1.10.1 先写测试 21
1.10.2 结对编程 22
1.11 为什么C++会成功 22
1.11.1 一个较好的C 22
1.11.2 延续式的学习过程 23
1.11.3 效率 23
1.11.4 系统更容易表达和理解 23
1.11.5 尽量使用库 23
1.11.6 利用模板的源代码重用 24
1.11.7 错误处理 24
1.11.8 大型程序设计 24
1.12 为向OOP转变而采取的策略 24
1.12.1 指导方针 25
1.12.1.1 训练 25
1.12.1.2 低风险项目 25
1.12.1.3 来自成功的模型 25
1.12.1.4 使用已有的类库 25
1.12.1.5 不要用C++重写已有的代码 25
1.12.2 管理的障碍 25
1.12.2.1 启动的代价 26
1.12.2.2 性能问题 26
1.12.2.3 常见的设计错误 26
1.13 小结 27
第2章 对象的创建与使用 28
2.1 语言的翻译过程 28
2.1.1 解释器 28
2.1.2 编译器 29
2.1.3 编译过程 29
2.1.3.1 静态类型检查 30
2.2 分段编译工具 30
2.2.1 声明与定义 30
2.2.1.1 函数声明的语法 31
2.2.1.2 一点说明 31
2.2.1.3 函数的定义 31
2.2.1.4 变量声明的语法 32
2.2.1.5 包含头文件 33
2.2.1.6 标准C++include语句格式 33
2.2.2 连接 34
2.2.3 使用库文件 34
2.2.3.1 连接器如何查找库 34
2.2.3.2 秘密的附加模块 35
2.2.3.3 使用简单的C语言库 35
2.3 编写第一个C++程序 35
2.3.1 使用iostream类 35
2.3.2 名字空间 36
2.3.3 程序的基本结构 37
2.3.4 "Hello,World!" 37
2.3.5 运行编译器 38
2.4 关于输入输出流 38
2.4.1 字符数组的拼接 39
2.4.2 读取输入数据 39
2.4.3 调用其他程序 40
2.5 字符串简介 40
2.6 文件的读写 41
2.7 vector简介 42
2.8 小结 45
2.9 练习 46
第3章 C++中的C 47
3.1 创建函数 47
3.1.1 函数的返回值 48
3.1.2 使用C的函数库 49
3.1.3 通过库管理器创建自己的库 49
3.2 执行控制语句 50
3.2.1 真和假 50
3.2.2 if-else语句 50
3.2.3 while语句 51
3.2.4 do-while语句 51
3.2.5 for语句 52
3.2.6 关键字break和continue 53
3.2.7 switch语句 54
3.2.8 使用和滥用goto 55
3.2.9 递归 55
3.3 运算符简介 56
3.3.1 优先级 56
3.3.2 自增和自减 57
3.4 数据类型简介 57
3.4.1 基本内部类型 57
3.4.2 bool类型与true和false 58
3.4.3 说明符 59
3.4.4 指针简介 60
3.4.5 修改外部对象 62
3.4.6 C++引用简介 64
3.4.7 用指针和引用作为修饰符 65
3.5 作用域 66
3.5.1 实时定义变量 67
3.6 指定存储空间分配 68
3.6.1 全局变量 68
3.6.2 局部变量 69
3.6.2.1 寄存器变量 69
3.6.3 静态变量 70
3.6.4 外部变量 71
3.6.4.1 连接 71
3.6.5 常量 72
3.6.5.1 常量值 72
3.6.6 volatile变量 73
3.7 运算符及其使用 73
3.7.1 赋值 73
3.7.2 数学运算符 73
3.7.2.1 预处理宏介绍 74
3.7.3 关系运算符 75
3.7.4 逻辑运算符 75
3.7.5 位运算符 75
3.7.6 移位运算符 76
3.7.7 一元运算符 78
3.7.8 三元运算符 78
3.7.9 逗号运算符 79
3.7.10 使用运算符时的常见问题 79
3.7.11 转换运算符 80
3.7.12 C++的显式转换 80
3.7.12.1 静态转换(static_cast) 81
3.7.12.2 常量转换(const_cast) 82
3.7.12.3 重解释转换(reinterpret_cast) 82
3.7.13 sizeof——独立运算符 83
3.7.14 asm关键字 84
3.7.15 显式运算符 84
3.8 创建复合类型 84
3.8.1 用typedef命名别名 85
3.8.2 用struct把变量结合在一起 85
3.8.2.1 指针和struct 87
3.8.3 用enum提高程度清晰度 87
3.8.3.1 枚举类型检查 88
3.8.4 用union节省内存 88
3.8.5 数组 89
3.8.5.1 指针和数组 91
3.8.5.2 探究浮点格式 93
3.8.5.3 指针算术 94
3.9 调试技巧 96
3.9.1 调试标记 96
3.9.1.1 预处理器调试标记 97
3.9.1.2 运行期调试标记 97
3.9.2 把变量和表达式转换成字符串 98
3.9.3 C语言assert()宏 98
3.10 函数地址 99
3.10.1 定义函数指针 99
3.10.2 复杂的声明和定义 99
3.10.3 使用函数指针 100
3.10.4 指向函数的指针数组 101
3.11 make:管理分段编译 101
3.11.1 make的行为 102
3.11.1.1 宏 102
3.11.1.2 后缀规则 103
3.11.1.3 默认目标 103
3.11.2 本书中的makefile 104
3.11.3 makefile的一个例子 104
3.12 小结 106
3.13 练习 106
第4章 数据抽象 109
4.1 一个袖珍C库 109
4.1.1 动态存储分配 112
4.1.2 有害的猜测 114
4.2 哪儿出问题 115
4.3 基本对象 116
4.4 什么是对象 120
4.5 抽象数据类型 121
4.6 对象细节 121
4.7 头文件形式 122
4.7.1 头文件的重要性 122
4.7.2 多次声明问题 123
4.7.3 预处理器指示#define、#ifdef和#endif 124
4.7.4 头文件的标准 124
4.7.5 头文件中的名字空间 125
4.7.6 在项目中使用头文件 125
4.8 嵌套结构 126
4.8.1 全局作用域解析 128
4.9 小结 129
4.10 练习 129
第5章 隐藏实现 132
5.1 设置限制 132
5.2 C++的访问控制 132
5.2.1 protected说明符 134
5.3 友元 134
5.3.1 嵌套友元 136
5.3.2 它是纯面向对象的吗 138
5.4 对象布局 138
5.5 类 139
5.5.1 用访问控制来修改Stash 141
5.5.2 用访问控制来修改Stack 141
5.6 句柄类 142
5.6.1 隐藏实现 142
5.6.2 减少重复编译 142
5.7 小结 144
5.8 练习 144
第6章 初始化与清除 146
6.1 用构造函数确保初始化 146
6.2 用析构函数确保清除 147
6.3 清除定义块 149
6.3.1 for循环 150
6.3.2 内存分配 151
6.4 带有构造函数和析构函数的Stash 152
6.5 带有构造函数和析构函数的Stack 154
6.6 集合初始化 156
6.7 默认构造函数 158
6.8 小结 159
6.9 练习 159
第7章 函数重载与默认参数 161
7.1 名字修饰 162
7.1.1 用返回值重载 162
7.1.2 类型安全连接 162
7.2 重载的例子 163
7.3 联合 166
7.4 默认参数 168
7.4.1 占位符参数 169
7.5 选择重载还是默认参数 170
7.6 小结 173
7.7 练习 173
第8章 常量 175
8.1 值替代 175
8.1.1 头文件里的const 176
8.1.2 const的安全性 176
8.1.3 集合 177
8.1.4 与C语言的区别 177
8.2 指针 178
8.2.1 指向const的指针 179
8.2.2 const指针 179
8.2.2.1 格式 180
8.2.3 赋值和类型检查 180
8.2.3.1 字符数组的字面值 180
8.3 函数参数和返回值 181
8.3.1 传递const值 181
8.3.2 返回const值 181
8.3.2.1 临时量 183
8.3.3 传递和返回地址 183
8.3.3.1 标准参数传递 185
8.4 类 185
8.4.1 类里的const 186
8.4.1.1 构造函数初始化列表 186
8.4.1.2 内部类型的“构造函数” 187
8.4.2 编译期间类里的常量 188
8.4.2.1 旧代码中的“enum hack” 189
8.4.3 const对象和成员函数 190
8.4.3.1 可变的:按位const和按逻辑const 192
8.4.3.2 只读存储能力 193
8.5 volatile 194
8.6 小结 195
8.7 练习 195
第9章 内联函数 197
9.1 预处理器的缺陷 197
9.1.1 宏和访问 199
9.2 内联函数 200
9.2.1 类内部的内联函数 200
9.2.2 访问函数 201
9.2.2.1 访问器和修改器 202
9.3 带内联函数的Stash和Stack 205
9.4 内联函数和编译器 208
9.4.1 限制 209
9.4.2 向前引用 209
9.4.3 在构造函数和析构函数里隐藏行为 210
9.5 减少混乱 210
9.6 预处理器的更多特征 211
9.6.1 标志粘贴 212
9.7 改进的错误检查 212
9.8 小结 215
9.9 练习 215
第10章 名字控制 217
10.1 来自C语言中的静态元素 217
10.1.1 函数内部的静态变量 217
10.1.1.1 函数内部的静态对象 218
10.1.1.2 静态对象的析构函数 219
10.1.2 控制连接 220
10.1.2.1 冲突问题 221
10.1.3 其他存储类型说明符 222
10.2 名字空间 222
10.2.1 创建一个名字空间 222
10.2.1.1 未命名的名字空间 223
10.2.1.2 友元 224
10.2.2 使用名字空间 224
10.2.2.1 作用域解析 224
10.2.2.2 使用指令 225
10.2.2.3 使用声明 226
10.2.3 名字空间的使用 227
10.3 C++中的静态成员 228
10.3.1 定义静态数据成员的存储 228
10.3.1.1 静态数组的初始化 229
10.3.2 嵌套类和局部类 231
10.3.3 静态成员函数 232
10.4 静态初始化的相依性 234
10.4.1 怎么办 235
10.4.1.1 技术一 235
10.4.1.2 技术二 237
10.5 替代连接说明 240
10.6 小结 240
10.7 练习 241
第11章 引用和拷贝构造函数 244
11.1 C++中的指针 244
11.2 C++中的引用 244
11.2.1 函数中的引用 245
11.2.1.1 常量引用 246
11.2.1.2 指针引用 246
11.2.2 参数传递准则 247
11.3 拷贝构造函数 247
11.3.1 按值传递和返回 247
11.3.1.1 传递和返回大对象 248
11.3.1.2 函数调用栈框架 248
11.3.1.3 重入 249
11.3.1.4 位拷贝与初始化 249
11.3.2 拷贝构造函数 251
11.3.2.1 临时对象 254
11.3.3 默认拷贝构造函数 255
11.3.4 替代拷贝构造函数的方法 256
11.3.4.1 防止按值传递 257
11.3.4.2 改变外部对象的函数 257
11.4 指向成员的指针 257
11.4.1 函数 259
11.4.1.1 一个例子 259
11.5 小结 261
11.6 练习 261
第12章 运算符重载 264
12.1 两个极端 264
12.2 语法 264
12.3 可重载的运算符 265
12.3.1 一元运算符 266
12.3.1.1 自增和自减 269
12.3.2 二元运算符 269
12.3.3 参数和返回值 278
12.3.3.1 作为常量通过传值方式返回 279
12.3.3.2 返回值优化 279
12.3.4 不常用的运算符 280
12.3.4.1 operator, 280
12.3.4.2 operator-> 280
12.3.4.3 嵌入的迭代器 282
12.3.4.4 operator-> 284
12.3.5 不能重载的运算符 285
12.4 非成员运算符 286
12.4.1 基本方针 287
12.5 重载赋值符 287
12.5.1 operator=的行为 288
12.5.1.1 类中指针 289
12.5.1.2 引用计数 291
12.5.1.3 自动创建operator= 295
12.6 自动类型转换 296
12.6.1 构造函数转换 296
12.6.1.1 阻止构造函数转换 297
12.6.2 运算符转换 297
12.6.2.1 反身性 298
12.6.3 类型转换例子 299
12.6.4 自动类型转换的缺陷 300
12.6.4.1 隐藏的行为 301
12.7 小结 302
12.8 练习 302
第13章 动态对象创建 305
13.1 对象创建 305
13.1.1 C从堆中获取存储单元的方法 306
13.1.2 operator new 307
13.1.3 operator delete 307
13.1.4 一个简单的例子 308
13.1.5 内存管理的开销 308
13.2 重新设计前面的例子 309
13.2.1 使用delete void可能会出错 309
13.2.2 对指针的清除责任 310
13.2.3 指针的Stash 310
13.2.3.1 一个测试程序 312
13.3 用于数组的new和delete 314
13.3.1 使指针更像数组 315
13.4 耗尽内存 315
13.5 重载new和delete 316
13.5.1 重载全局new和delete 317
13.5.2 对于一个类重载new和delete 318
13.5.3 为数组重载new和delete 320
13.5.4 构造函数调用 322
13.5.5 定位new和delete 323
13.6 小结 324
13.7 练习 324
第14章 继承和组合 326
14.1 组合语法 326
14.2 继承语法 327
14.3 构造函数的初始化表达式表 329
14.3.1 成员对象初始化 329
14.3.2 在初始化表达式表中的内部类型 329
14.4 组合和继承的联合 330
14.4.1 构造函数和析构函数调用的次序 331
14.5 名字隐藏 333
14.6 非自动继承的函数 336
14.6.1 继承和静态成员函数 339
14.7 组合与继承的选择 339
14.7.1 子类型设置 340
14.7.2 私有继承 342
14.7.2.1 对私有继承成员公有化 342
14.8 protected 343
14.8.1 protected继承 343
14.9 运算符的重载与继承 343
14.10 多重继承 345
14.11 渐增式开发 345
14.12 向上类型转换 346
14.12.1 为什么要“向上类型转换” 347
14.12.2 上类型转换和拷贝构造函数 347
14.12.3 组合与继承(再论) 349
14.12.4 指针和引用的向上类型转换 350
14.12.5 危机 350
14.13 小结 351
14.14 练习 351
第15章 多态性和虚函数 354
15.1 C++程序员的演变 354
15.2 向上类型转换 355
15.3 问题 356
15.3.1 函数调用捆绑 356
15.4 虚函数 356
15.4.1 扩展性 357
15.5 C++如何实现晚捆绑 359
15.5.1 存放类型信息 360
15.5.2 虚函数功能图示 361
15.5.3 撩开面纱 362
15.5.4 安装vpointer 363
15.5.5 对象是不同的 363
15.6 为什么需要虚函数 364
15.7 抽象基类和纯虚函数 365
15.7.1 纯虚定义 368
15.8 继承和VTABLE 368
15.8.1 对象切片 370
15.9 重载和重新定义 372
15.9.1 变量返回类型 373
15.10 虚函数和构造函数 375
15.10.1 构造函数调用次序 375
15.10.2 虚函数在构造函数中的行为 376
15.11 析构函数和虚拟析构函数 376
15.11.1 纯虚析构函数 378
15.11.2 析构函数中的虚机制 379
15.11.3 创建基于对象的继承 380
15.12 运算符重载 382
15.13 向下类型转换 384
15.14 小结 386
15.15 练习 387
第16章 模板介绍 390
16.1 容器 390
16.1.1 容器的需求 391
16.2 模板综述 392
16.2.1 模板方法 393
16.3 模板语法 394
16.3.1 非内联函数定义 395
16.3.1.1 头文件 396
16.3.2 作为模板的IntStack 396
16.3.3 模板中的常量 398
16.4 作为模板的Stash和Stack 399
16.4.1 模板化的指针Stash 401
16.5 打开和关闭所有权 405
16.6 以值存放对象 407
16.7 迭代器简介 408
16.7.1 带有迭代器的栈 415
16.7.2 带有迭代器的PStash 417
16.8 为什么使用迭代器 422
16.8.1 函数模板 424
16.9 小结 425
16.10 练习 425
附录A 编码风格 428
A.1 常规 428
A.2 文件名 428
A.3 开始和结束注释标记 429
A.4 圆括号、大括号和缩排 429
A.5 标识符名 432
A.6 头文件的包含顺序 432
A.7 在头文件上包含警卫 432
A.8 使用名字空间 433
A.9 require()和assure()的使用 433
附录B 编程准则 434
附录C 推荐读物 441
C.1 C 441
C.2 基本C++ 441
C.2.1 我自己的书 441
C.3 深入研究和死角分析 442
C.4 分析和设计 443
索引 445