《C++编程思想》(第1卷)(第2版)是C++领域一本权威的著作,书中的内容、讲授方法、选用例子和跟随练习既适合课堂教学,又适合读者自学。无论是高等院校计算机及相关专业的学生,还是业界的专业人员,以及广大的计算机爱好者,都可从阅读《C++编程思想》(第1卷)(第2版)中获得宝贵的收益。第2版与第1版相比,在章节安排上有以下改变。增加了两章:“对象的创建与使用”和“C++中的C”,前者与“对象导言”实际上是第1版“对象的演化”一章的彻底重写,增加了近几年面向对象方法和编程方法的最瓣研究与实践的有效成果,后者的添加使不熟悉C的读者可以直接使用《C++编程思想》(第1卷)(第2版)。删去了四章:“输入输出流介绍”、“多重继承”、“异常处理”和“运行时类型识别”,删去的内容属于C++中较复杂的主题,作者将它们连同C++标准完成后又增加的一些内容放到《C++编程思想》(第1卷)(第2版)的第2卷中,使得《C++编程思想》(第1卷)(第2版)的第1卷内容更加集中,供不同程度的读者选择阅读。需要强调的是,第2版的改变不仅体现在这些章节的调整上,更多的改变体现在每一章的字里行间中,包括例子的调整和练习的补充。与众不同的精心选材和认真推敲的叙述使得第2版更趋成熟。
目录
- 第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