内容简介
《21天学通C++(第8版)》通过大量短小精悍的程序详细而全面地阐述了C++基本概念和技术,以及C++11、C++14和C++17新增的功能,包括管理输入/输出、循环和数组、面向对象编程、模板、使用标准模板库、列表初始化、lambda表达式、自动类型推断等。这些内容被组织成结构合理、联系紧密的章节,每章都可在1小时内阅读完毕;每章都提供了示例程序清单,并辅以示例输出和代码分析,以阐述该章介绍的主题。为加深读者对所学内容的理解,每章末尾都提供了常见问题及其答案以及练习和测验。读者可对照附录E提供的测验和练习答案,了解自己对所学内容的掌握程度。 《21天学通C++++(第8版)》是针对C++初学者编写的,不要求读者有C语言方面的背景知识,可作为高等院校教授C++课程的教材,也可供初学者自学C++时使用。《21天学通C++(第8版)》通过大量短小精悍的程序详细而全面地阐述了C++基本概念和技术,以及C++11、C++14和C++17新增的功能,包括管理输入/输出、循环和数组、面向对象编程、模板、使用标准模板库、列表初始化、lambda表达式、自动类型推断等。这些内容被组织成结构合理、联系紧密的章节,每章都可在1小时内阅读完毕;每章都提供了示例程序清单,并辅以示例输出和代码分析,以阐述该章介绍的主题。为加深读者对所学内容的理解,每章末尾都提供了常见问题及其答案以及练习和测验。读者可对照附录E提供的测验和练习答案,了解自己对所学内容的掌握程度。
《21天学通C++(第8版)》是针对C++初学者编写的,不要求读者有C语言方面的背景知识,可作为高等院校教授C++课程的教材,也可供初学者自学C++时使用。
目录
第1章 绪论 1 1.1C++++简史 1 1.1.1与C语言的关系 1 1.1.2C++的优点 1 1.1.3C++标准的发展历程 2 1.1.4哪些人使用C++程序 2 1.2编写C++应用程序 2 1.2.1生成可执行文件的步骤 2 1.2.2分析并修复错误 2 1.2.3集成开发环境 3 1.2.4编写第一个C++应用程序 3 1.2.5生成并执行第一个C++应用程序 4 1.2.6理解编译错误 5 1.3C++新增的功能 5 1.4总结 5 1.5问与答 6 1.6作业 6 1.6.1测验 6 1.6.2练习 6 第2章 C++程序的组成部分 8 2.1HelloWorld程序的组成部分 8 2.1.1预处理器编译指令#include 9 2.1.2程序的主体—main() 9 2.1.3返回值 10 2.2名称空间的概念 10 2.3C++代码中的注释 11 2.4C++函数 12 2.5使用std::cin和std::cout执行基本输入 输出操作 14 2.6总结 15 2.7问与答 15 2.8作业 15 2.8.1测验 16 2.8.2练习 16 第3章 使用变量和常量 17 3.1什么是变量 17 3.1.1内存和寻址概述 17 3.1.2声明变量以访问和使用内存 17 3.1.3声明并初始化多个类型相同的 变量 19 3.1.4理解变量的作用域 19 3.1.5全局变量 20 3.1.6命名约定 22 3.2编译器支持的常见C++变量类型 22 3.2.1使用bool变量存储布尔值 23 3.2.2使用char变量存储字符 23 3.2.3有符号整数和无符号整数的概念 24 3.2.4有符号整型short、int、long和longlong 24 3.2.5无符号整型unsigned short、unsigned int、unsigned long和unsigned long long 25 3.2.6选择正确的数据类型以免发生溢出错误 25 3.2.7浮点类型float和double 26 3.3使用sizeof确定变量的长度 26 3.4使用auto自动推断类型 28 3.5使用typedef替换变量类型 29 3.6什么是常量 30 3.6.1字面常量 30 3.6.2使用const将变量声明为常量 30 3.6.3使用constexpr定义常量表达式 31 3.6.4枚举 32 3.6.5使用#define定义常量 34 3.7不能用作常量或变量名的关键字 34 3.8总结 35 3.9问与答 36 3.10作业 37 3.10.1测验 37 3.10.2练习 37 第4章 管理数组和字符串 38 4.1什么是数组 38 4.1.1为何需要数组 38 4.1.2声明和初始化静态数组 39 4.1.3数组中的数据是如何存储的 39 4.1.4访问存储在数组中的数据 40 4.1.5修改存储在数组中的数据 41 4.2多维数组 43 4.2.1声明和初始化多维数组 44 4.2.2访问多维数组中的元素 44 4.3动态数组 45 4.4C风格字符串 46 4.5C++字符串:使用std::string 48 4.6总结 50 4.7问与答 50 4.8作业 50 4.8.1测验 51 4.8.2练习 51 第5章 使用表达式、语句和运算符 52 5.1语句 52 5.2复合语句(语句块) 53 5.3使用运算符 53 5.3.1赋值运算符(=) 53 5.3.2理解左值和右值 53 5.3.3加法运算符(+)、减法运算符()、乘法运算符(*)、除法运算符(/)和求模运算符(%) 53 5.3.4递增运算符(++)和递减运算符() 54 5.3.5前缀还是后缀 55 5.3.6相等运算符(==)和不等运算符(!=) 56 5.3.7关系运算符 56 5.3.8逻辑运算NOT、AND、OR和XOR 58 5.3.9使用C++逻辑运算NOT(!)、AND(&&)和OR(||) 59 5.3.10按位运算符NOT(~)、AND(&)、OR(|)和XOR(;) 63 5.3.11按位右移运算符(>>)和左移运算符(<<) 64 5.3.12复合赋值运算符 65 5.3.13使用运算符sizeof确定变量占用的内存量 67 5.3.14运算符优先级 68 5.4总结 69 5.5问与答 69 5.6作业 70 5.6.1测验 70 5.6.2练习 70 第6章 控制程序流程 71 6.1使用if…else有条件地执行 71 6.1.1使用if…else进行条件编程 72 6.1.2有条件地执行多条语句 73 6.1.3嵌套if语句 74 6.1.4使用switch—case进行条件处理 77 6.1.5使用运算符:进行条件处理 80 6.2在循环中执行代码 81 6.2.1不成熟的goto循环 81 6.2.2while循环 83 6.2.3do…while循环 84 6.2.4for循环 86 6.2.5基于范围的for循环 88 6.3使用continue和break修改循环的行为 90 6.3.1不结束的循环—无限循环 90 6.3.2控制无限循环 91 6.4编写嵌套循环 93 6.4.1使用嵌套循环遍历多维数组 94 6.4.2使用嵌套循环计算斐波纳契数列 95 6.5总结 96 6.6问与答 96 6.7作业 97 6.7.1测验 97 6.7.2练习 97 第7章 使用函数组织代码 99 7.1为何需要函数 99 7.1.1函数原型是什么 100 7.1.2函数定义是什么 101 7.1.3函数调用和实参是什么 101 7.1.4编写接受多个参数的函数 101 7.1.5编写没有参数和返回值的函数 103 7.1.6带默认值的函数参数 103 7.1.7递归函数—调用自己的函数 105 7.1.8包含多条return语句的函数 106 7.2使用函数处理不同类型的数据 107 7.2.1函数重载 107 7.2.2将数组传递给函数 109 7.2.3按引用传递参数 110 7.3微处理器如何处理函数调用 111 7.3.1内联函数 112 7.3.2自动推断返回类型 113 7.3.3lambda函数 114 7.4总结 115 7.5问与答 116 7.6作业 116 7.6.1测验 116 7.6.2练习 116 第8章 阐述指针和引用 118 8.1什么是指针 118 8.1.1声明指针 119 8.1.2使用引用运算符(&)获取变量的地址 119 8.1.3使用指针存储地址 120 8.1.4使用解除引用运算符(*)访问指向的数据 122 8.1.5将sizeof()用于指针的结果 124 8.2动态内存分配 125 8.2.1使用new和delete动态地分配和释放内存 125 8.2.2将递增和递减运算符(++和)用于指针的结果 127 8.2.3将关键字const用于指针 129 8.2.4将指针传递给函数 130 8.2.5数组和指针的类似之处 131 8.3使用指针时常犯的编程错误 133 8.3.1内存泄露 133 8.3.2指针指向无效的内存单元 133 8.3.3悬浮指针(也叫迷途或失控指针) 134 8.3.4检查使用new发出的分配请求是否得到满足 135 8.4指针编程佳实践 137 8.5引用是什么 137 8.5.1是什么让引用很有用 138 8.5.2将关键字const用于引用 139 8.5.3按引用向函数传递参数 140 8.6总结 140 8.7问与答 141 8.8作业 142 8.8.1测验 142 8.8.2练习 142 第9章 类和对象 144 9.1类和对象 144 9.1.1声明类 145 9.1.2作为类实例的对象 145 9.1.3使用句点运算符访问成员 146 9.1.4使用指针运算符(—>)访问成员 146 9.2关键字public和private 147 9.3构造函数 150 9.3.1声明和实现构造函数 150 9.3.2何时及如何使用构造函数 151 9.3.3重载构造函数 152 9.3.4没有默认构造函数的类 154 9.3.5带默认值的构造函数参数 155 9.3.6包含初始化列表的构造函数 156 9.4析构函数 157 9.4.1声明和实现析构函数 157 9.4.2何时及如何使用析构函数 158 9.5复制构造函数 160 9.5.1浅复制及其存在的问题 160 9.5.2使用复制构造函数确保深复制 162 9.5.3有助于改善性能的移动构造函数 166 9.6构造函数和析构函数的其他用途 166 9.6.1不允许复制的类 167 9.6.2只能有一个实例的单例类 167 9.6.3禁止在栈中实例化的类 169 9.6.4使用构造函数进行类型转换 171 9.7this指针 172 9.8将sizeof()用于类 173 9.9结构不同于类的地方 175 9.10声明友元 176 9.11共用体:一种特殊的数据存储机制 178 9.11.1声明共用体 178 9.11.2在什么情况下使用共用体 178 9.12对类和结构使用聚合初始化 180 9.13总结 183 9.14问与答 183 9.15作业 184 9.15.1测验 184 9.15.2练习 184 第10章 实现继承 185 10.1继承基础 185 10.1.1继承和派生 186 10.1.2C++++派生语法 186 10.1.3访问限定符protected 188 10.1.4基类初始化—向基类传递参数 190 10.1.5在派生类中覆盖基类的方法 192 10.1.6调用基类中被覆盖的方法 194 10.1.7在派生类中调用基类的方法 194 10.1.8在派生类中隐藏基类的方法 196 10.1.9构造顺序 198 10.1.10析构顺序 198 10.2私有继承 200 10.3保护继承 202 10.4切除问题 205 10.5多继承 205 10.6使用final禁止继承 207 10.7总结 208 10.8问与答 208 10.9作业 208 10.9.1测验 208 10.9.2练习 209 第11章 多态 210 11.1多态基础 210 11.1.1为何需要多态行为 210 11.1.2使用虚函数实现多态行为 212 11.1.3为何需要虚构造函数 213 11.1.4虚函数的工作原理—理解虚函数表 217 11.1.5抽象基类和纯虚函数 220 11.2使用虚继承解决菱形问题 222 11.3表明覆盖意图的限定符override 225 11.4使用final来禁止覆盖函数 226 11.5可将复制构造函数声明为虚函数吗 227 11.6总结 230 11.7问与答 230 11.8作业 231 11.8.1测验 231 11.8.2练习 231 第12章 运算符类型与运算符重载 232 12.1C++运算符 232 12.2单目运算符 233 12.2.1单目运算符的类型 233 12.2.2单目递增与单目递减运算符 234 12.2.3转换运算符 236 12.2.4解除引用运算符(*)和成员选择运算符(—>) 238 12.3双目运算符 239 12.3.1双目运算符的类型 240 12.3.2双目加法与双目减法运算符 240 12.3.3实现运算符+=与= 242 12.3.4重载等于运算符(==)和不等运算符(!=) 243 12.3.5重载运算符<、>、<=和>= 245 12.3.6重载复制赋值运算符(=) 248 12.3.7下标运算符 250 12.4函数运算符operator() 253 12.5用于高性能编程的移动构造函数和移动赋值运算符 254 12.5.1不必要的复制带来的问题 254 12.5.2声明移动构造函数和移动赋值运算符 254 12.6用户定义的字面量 258 12.7不能重载的运算符 260 12.8总结 261 12.9问与答 261 12.10作业 261 12.10.1测验 261 12.10.2练习 261 第13章 类型转换运算符 262 13.1为何需要类型转换 262 13.2为何有些C++程序员不喜欢C风格类型转换 263 13.3C++类型转换运算符 263 13.3.1使用static_cast 263 13.3.2使用dynamic_cast和运行阶段类型识别 264 13.3.3使用reinterpret_cast 267 13.3.4使用const_cast 267 13.4C++类型转换运算符存在的问题 268 13.5总结 269 13.6问与答 269 13.7作业 270 13.7.1测验 270 13.7.2练习 270 第14章 宏和模板简介 271 14.1预处理器与编译器 271 14.2使用#define定义常量 271 14.3使用#define编写宏函数 274 14.3.1为什么要使用括号 276 14.3.2使用assert宏验证表达式 276 14.3.3使用宏函数的优点和缺点 277 14.4模板简介 278 14.4.1模板声明语法 278 14.4.2各种类型的模板声明 279 14.4.3模板函数 279 14.4.4模板与类型安全 281 14.4.5模板类 281 14.4.6声明包含多个参数的模板 282 14.4.7声明包含默认参数的模板 283 14.4.8一个模板示例 283 14.4.9模板的实例化和具体化 284 14.4.10模板类和静态成员 286 14.4.11参数数量可变的模板 287 14.4.12使用static_assert执行编译阶段检查 290 14.4.13在实际C++编程中使用模板 290 14.5总结 291 14.6问与答 291 14.7作业 291 14.7.1测验 291 14.7.2练习 292 第15章 标准模板库简介 293 15.1STL容器 293 15.1.1顺序容器 293 15.1.2关联容器 294 15.1.3容器适配器 294 15.2STL迭代器 295 15.3STL算法 295 15.4使用迭代器在容器和算法之间交互 295 15.5选择正确的容器 297 15.6STL字符串类 298 15.7总结 298 15.8问与答 299 15.9作业 299 第16章 STL string类 300 16.1为何需要字符串操作类 300 16.2使用STL string类 301 16.2.1实例化和复制STL string 301 16.2.2访问std::string的字符内容 303 16.2.3拼接字符串 305 16.2.4在string中查找字符或子字符串 306 16.2.5截短STL string 307 16.2.6字符串反转 309 16.2.7字符串的大小写转换 310 16.3基于模板的STL string实现 311 16.4总结 312 16.5问与答 312 16.6作业 313 16.6.1测验 313 16.6.2练习 313 第17章 STL动态数组类 314 17.1std::vector的特点 314 17.2典型的vector操作 314 17.2.1实例化vector 314 17.2.2使用push_back()在末尾插入元素 316 17.2.3列表初始化 317 17.2.4使用insert()在指定位置插入元素 317 17.2.5使用数组语法访问vector中的元素 319 17.2.6使用指针语法访问vector中的元素 320 17.2.7删除vector中的元素 321 17.3理解大小和容量 322 17.4STLdeque类 324 17.5总结 326 17.6问与答 326 17.7作业 327 17.7.1测验 327 17.7.2练习 327 第18章 STLlist和forward_list 328 18.1std::list的特点 328 18.2基本的list操作 328 18.2.1实例化std::list对象 328 18.2.2在list开头或末尾插入元素 330 18.2.3在list中间插入元素 331 18.2.4删除list中的元素 333 18.3对list中的元素进行反转和排序 334 18.3.1使用list::reverse()反转元素的排列顺序 334 18.3.2对元素进行排序 335 18.3.3对包含对象的list进行排序以及删除其中的元素 337 18.3.4C++11引入的std::forward_list 340 18.4总结 341 18.5问与答 342 18.6作业 342 18.6.1测验 342 18.6.2练习 342 第19章 STL集合类 343 19.1简介 343 19.2STLset和multiset的基本操作 344 19.2.1实例化std::set对象 344 19.2.2在set或multiset中插入元素 345 19.2.3在STLset或multiset中查找元素 347 19.2.4删除STLset或multiset中的元素 348 19.3使用STLset和multiset的优缺点 352 19.4总结 354 19.5问与答 355 19.6作业 355 19.6.1测验 355 19.6.2练习 355 第20章 STL映射类 356 20.1STL映射类简介 356 20.2STLmap和multimap的基本操作 357 20.2.1实例化std::map和std::multimap 357 20.2.2在STLmap或multimap中插入元素 358 20.2.3在STLmap或multimap中查找元素 361 20.2.4在STLmultimap中查找元素 363 20.2.5删除STLmap或multimap中的元素 363 20.3提供自定义的排序谓词 365 20.4基于散列表的STL键—值对容器 368 20.4.1散列表的工作原理 368 20.4.2使用unordered_map和unordered_multimap 368 20.5总结 372 20.6问与答 372 20.7作业 372 20.7.1测验 373 20.7.2练习 373 第21章 理解函数对象 374 21.1函数对象与谓词的概念 374 21.2函数对象的典型用途 374 21.2.1一元函数 374 21.2.2一元谓词 378 21.2.3二元函数 380 21.2.4二元谓词 381 21.3总结 383 21.4问与答 384 21.5作业 384 21.5.1测验 384 21.5.2练习 384 第22章 lambda表达式 385 22.1lambda表达式是什么 385 22.2如何定义lambda表达式 386 22.3一元函数对应的lambda表达式 386 22.4一元谓词对应的lambda表达式 387 22.5通过捕获列表接受状态变量的lambda表达式 388 22.6lambda表达式的通用语法 390 22.7二元函数对应的lambda表达式 391 22.8二元谓词对应的lambda表达式 392 22.9总结 394 22.10问与答 394 22.11作业 395 22.11.1测验 395 22.11.2练习 395 第23章 STL算法 396 23.1什么是STL算法 396 23.2STL算法的分类 396 23.2.1非变序算法 396 23.2.2变序算法 397 23.3使用STL算法 398 23.3.1根据值或条件查找元素 398 23.3.2计算包含给定值或满足给定条件的元素数 400 23.3.3在集合中搜索元素或序列 401 23.3.4将容器中的元素初始化为指定值 403 23.3.5使用std::generate()将元素设置为运行阶段生成的值 405 23.3.6使用for_each()处理指定范围内的元素 406 23.3.7使用std::transform()对范围进行变换 407 23.3.8复制和删除操作 409 23.3.9替换值以及替换满足给定条件的元素 412 23.3.10排序、在有序集合中搜索以及删除重复元素 413 23.3.11将范围分区 415 23.3.12在有序集合中插入元素 417 23.4总结 419 23.5问与答 419 23.6作业 419 23.6.1测验 420 23.6.2练习 420 第24章 自适应容器:栈和队列 421 24.1栈和队列的行为特征 421 24.1.1栈 421 24.1.2队列 422 24.2使用STLstack类 422 24.2.1实例化stack 422 24.2.2stack的成员函数 423 24.2.3使用push()和pop()在栈顶插入和删除元素 424 24.3使用STLqueue类 425 24.3.1实例化queue 425 24.3.2queue的成员函数 426 24.3.3使用push()在队尾插入以及使用pop()从队首删除 427 24.4使用STL优先级队列 428 24.4.1实例化priority_queue类 428 24.4.2priority_queue的成员函数 429 24.4.3使用push()在priority_queue末尾插入以及使用pop()在priority_queue开头删除 430 24.5总结 432 24.6问与答 432 24.7作业 432 24.7.1测验 432 24.7.2练习 432 第25章 使用STL位标志 433 25.1bitset类 433 25.2使用std::bitset及其成员 434 25.2.1std:bitset的运算符 434 25.2.2std::bitset的成员方法 435 25.3vector<bool> 437 25.3.1实例化vector<bool> 437 25.3.2vector<bool>的成员函数和运算符 438 25.4总结 439 25.5问与答 439 25.6作业 439 25.6.1测验 439 25.6.2练习 440 第26章 理解智能指针 441 26.1什么是智能指针 441 26.1.1常规(原始)指针存在的问题 441 26.1.2智能指针有何帮助 442 26.2智能指针是如何实现的 442 26.3智能指针类型 443 26.3.1深复制 443 26.3.2写时复制机制 445 26.3.3引用计数智能指针 445 26.3.4引用链接智能指针 445 26.3.5破坏性复制 445 26.3.6使用std::unique_ptr 447 26.4深受欢迎的智能指针库 449 26.5总结 449 26.6问与答 449 26.7作业 450 26.7.1测试 450 26.7.2练习 450 第27章 使用流进行输入和输出 451 27.1流的概述 451 27.2重要的C++流类和流对象 452 27.3使用std::cout将指定格式的数据写入控制台 453 27.3.1使用std::cout修改数字的显示格式 453 27.3.2使用std::cout对齐文本和设置字段宽度 455 27.4使用std::cin进行输入 455 27.4.1使用std::cin将输入读取到基本类型变量中 455 27.4.2使用std::cin:get将输入读取到char*缓冲区中 456 27.4.3使用std::cin将输入读取到std::string中 457 27.5使用std::fstream处理文件 458 27.5.1使用open()和close()打开和关闭文件 459 27.5.2使用open()创建文本文件并使用运算符<<写入文本 460 27.5.3使用open()和运算符>>读取文本文件 460 27.5.4读写二进制文件 461 27.6使用std::stringstream对字符串进行转换 463 27.7总结 464 27.8问与答 464 27.9作业 465 27.9.1测验 465 27.9.2练习 465 第28章 异常处理 466 28.1什么是异常 466 28.2导致异常的原因 466 28.3使用try和catch捕获异常 467 28.3.1使用catch(…)处理所有异常 467 28.3.2捕获特定类型的异常 468 28.3.3使用throw引发特定类型的异常 469 28.4异常处理的工作原理 470 28.4.1std::exception类 472 28.4.2从std::exception派生出自定义异常类 473 28.5总结 474 28.6问与答 474 28.7作业 475 28.7.1测验 475 28.7.2练习 475 第29章 继续前行 477 29.1当今的处理器有何不同 477 29.2如何更好地利用多个内核 478 29.2.1线程是什么 478 29.2.2为何要编写多线程应用程序 479 29.2.3线程如何交换数据 479 29.2.4使用互斥量和信号量同步线程 480 29.2.5多线程技术带来的问题 480 29.3编写杰出的C++代码 480 29.4C++17有望引入的新特性 481 29.4.1支持在if和switch中进行初始化 481 29.4.2保证复制得以避免 482 29.4.3避免内存分配开销的std::string_view 482 29.4.4类型安全的共用体替代品std::variant 483 29.4.5使用ifconstexpr有条件地编译代码 483 29.4.6改进的lambda表达式 484 29.4.7在构造函数中使用类型自动推断功能 484 29.5更深入地学习C++ 484 29.5.1在线文档 485 29.5.2提供指南和帮助的社区 485 29.6总结 485 29.7问与答 485 29.8作业 485 附录A 二进制和十六进制 486 A.1十进制 486 A.2二进制 486 A.2.1计算机为何使用二进制 487 A.2.2位和字节 487 A.2.31KB相当于多少字节 487 A.3十六进制 487 A.4不同进制之间的转换 488 A.4.1通用转换步骤 488 A.4.2从十进制转换为二进制 488 A.4.3从十进制转换为十六进制 489 附录B C++关键字 490 附录C 运算符优先级 491 附录D ASCII码 492 附录E 答案 495 · · · · · · (收起)