e^{i\pi} + 1
—— Leonhard Euler
本章汇集了各种信息, 旨在让你对本书其余部分有初步了解. 请略读本章, 细读其中你感兴趣的部分. 在编写任何代码之前, 请阅读 :ref:`天鹅书支持库`. 对于教师, 可以发现大部分内容都是直接有用的. 如果你是作为初学者阅读本书, 请不要试图理解本章所有内容. 待你感觉能自如编写和执行小规模的程序时, 你可能需要回过头来重读本章.
本书包含三个部分:
- 第一部分, 基础知识
- 第 1 章至第 8 章. 介绍了程序设计的基本概念和技术, 以及开始编写代码所需的 C++ 语言和库设施. 这包括类型系统、算术运算、控制结构、错误处理, 以及函数和用户自定义类型的设计、实现和使用.
- 第二部分, 输入和输出
- 第 9 章至第 14 章. 首先描述了如何从键盘和文件中获取数字和文本数据, 以及如何在屏幕和文件中产生相应的输出. 接着, 我们展示如何将数字数据、文本和几何形状呈现为图形输出, 以及如何从图形用户界面 (Graphical User Interface, GUI) 中获取程序的输入. 作为其中的一部分, 我们介绍了面向对象程序设计的基本原理和技术.
- 第三部分, 数据与算法
- 第 15 章至第 21 章. 聚焦于 C++ 标准库的容器和算法框架 (通常被称为 STL). 我们展示了容器 (例如 :cpp:`vector`、:cpp:`list` 和 :cpp:`map`) 的实现和使用. 在此过程中, 我们引入了指针、数组和动态内存等底层设施. 我们还展示了如何用异常处理错误, 以及如何通过模板参数化我们的类和函数. 作为其中的一部分, 我们介绍了泛型程序设计的基本原理和技术. 此外, 我们还演示了如何设计和使用标准库算法 (如 :cpp:`sort`、:cpp:`find` 和 :cpp:`inner_product`).
主题的顺序安排由程序设计技术而非编程语言特性决定的.
CC 为了便于你复习, 以及帮助你在初次阅读、尚未确定哪些内容非常重要时不遗漏关键点, 我们在页边空白处放置了三种 "警示标记":
- CC: 概念 (concepts) 与技术 (techniques) (本段为该主题的一个示例)
- AA: 建议 (advice)
- XX: 警告 (warning)
使用 CC、AA 和 XX, 而不是使用单个符号的不同颜色, 是为了在颜色难以区分的情况下提供帮助. (译注: 译文中难以表现它的颜色和样式, 仅在对应段落最前面进行了标识.)
本书中我们直接与你对话. 这种方式比大多科学论文中约定俗成的专业间接称呼更简单、更清晰. 当我们说 "你" 时, 我们是指 "你这位读者", 而当我们说 "我们" 时, 我们要么指的是 "你跟我们这些作者和老师" 一起来解决一个问题, 就像我们在同一个房间会做的那样. 当我提及我自己的贡献或个人观点时, 我使用 "我" 来表达.
AA 本书的内容组织适合从头到尾逐章阅读, 当然, 你也常常要回过头来对某些内容读上第二遍、第三遍. 实际上, 这是唯一合理的方法, 因为当遇到还看不出什么门道的地方时, 你通常会快速掠过. 对于这种情况, 你最终还是需要再次回到这个地方. 尽管书后有索引且书中有交叉引用, 但这不是一本你随便翻开一页开始学习还妄想能学懂的书. 本书每一节、每一章的内容安排, 都假定你已经理解了之前的内容.
本书的每一章都是一个合理的自包含单元, 这意味着应一口气读完 (当然这只是理论上, 实际上由于学生紧密的学习计划, 不总是可行). 这是将内容划分为章的主要标准. 其他标准包括: 从简单练习 (drill) 和习题 (exercise) 的角度, 每章是一个合适的单元; 每一章提出一些特定的概念、思想或技术. 这种标准的多样性使得少数章过长, 所以不要教条地遵循 "一口气读完" 的准则. 特别是当你已经脑内回答了思考题 (review question), 完成了简单练习, 并做了一些习题时, 你通常会发现你需要回过头去重读一些小节 (section).
对一本教科书常见的赞誉是: "它回答了我所有的问题, 就在我刚好想到这些问题的时候!" 这对细节技术问题是很理想的, 而早期的读者也发现本书有这样的特性. 但是, 这还不够理想. 我们提出初学者可能未曾想到的问题. 我们的目标是, 提出并回答那些你在编写供他人使用的高质量软件时需要考虑的问题. 学习回答好的 (通常也是困难的) 问题是学习如何像一个程序员那样思考所必需的. 只回答那些简单的、浅显的问题会使你感觉良好, 但无助于你成长为一名程序员.
我们努力尊重你的智力, 珍惜你的时间. 在陈述时, 我们追求的是专业口吻而不是可爱口吻, 并且我们宁可低调表达一个观点也不大肆渲染它. 我们尽力不夸大一种程序设计技术或一个语言特性的重要性, 但请不要因此低估 "这通常是有用的" 这种简单陈述的重要程度. 如果我们不经意间强调某些内容是重要的, 那是想说明, 你如果不掌握它, 或早或晚都会因此而浪费时间.
我们对幽默的运用比我们本来希望的要有限, 但经验表明, 人们对什么是有趣的想法差异巨大, 而一次失败的幽默尝试可能会引起困惑.
我们不会伪称本书中的思想和工具是完美的. 实际上没有任何一种工具、库、语言或者技术能够解决程序员所面临的所有难题, 至多能帮助你开发、表达你的问题求解方案而已. 我们尽量避免 "无害的谎言", 也就是说, 我们会尽力避免过于简单的解释, 虽然这些解释清晰易懂, 但在实际编程和问题求解时却并不真实.
程序设计不仅仅是一种脑力活动, 实际动手编写程序是掌握程序设计技巧必不可少的一环. 本书提供三个层次的程序设计练习:
- 简单练习
- 简单练习是一种非常简单的习题, 其目的是帮助学生掌握一些相对死板的实际编程技巧. 一个简单练习通常由一系列的单个程序修改练习组成. 你应该完成所有简单练习. 完成简单练习不需要很强的理解能力、很聪明或者很有创造性. 我们将简单练习作为本书的基本组成部分. 如果你没有完成简单练习, 就不能说 "完成" 了本书的学习.
- 习题
- 有些习题比较简单, 有些则很难, 但多数习题都是想给学生留下一定的创造和想象空间. 如果时间紧张, 你可以做少量习题, 但题量至少应该能使你弄清楚哪些内容对你来说比较困难. 在此基础上应该再多做一些. 这样你将能学到最多知识. 我们希望本书的习题都是学生能够做出来的, 而不是需要超乎常人的智力才能解答的复杂难题. 但是, 我们还是希望我们提供的习题能给你足够多的挑战, 能耗尽甚至是最好的学生的所有时间. 我们不期待你能完成所有习题, 但请尽情尝试.
- 试试这个 (try this)
- 有些人喜欢把书放在一边, 在读完一章之前先尝试一些例子; 而另一些人则喜欢先读完整章, 然后再尝试运行代码. 为了支持有前一种偏好的读者, 我们提供了一些简单的实践任务建议. 它们以 试试这个 开头, 添加在在文内分段处. 试试这个 通常是一种简单练习, 但仅聚焦于前面刚刚介绍的主题. 如果你略过了一个 试试这个 而没有尝试它——可能因为你身边没有电脑或者你被之后的内容吸引——那么最好在做本章的简单练习时回头去做一下这个题目; "试一试" 要么是该章简单练习的补充, 要么干脆就是其中的一部分.
此外, 每章末尾我们都提供了一些帮助来巩固所学的内容:
- 思考题
- 在每章末尾你都会看到一些思考题. 这些思考题是想为你指出这一章中的重点内容. 一种学习思考题的方法是把它们作为习题的补充: 习题关注程序设计的实践层面, 而思考题则试图帮你强化思想和概念. 因此, 思考题有点像出色的面试题.
- 术语 (terms)
- 每章最后都有 "术语" 一节, 给出本章中提出的程序设计或 C++ 方面的基本词汇表. 如果你希望理解别人关于程序设计的陈述, 或者想明确表达出自己的思想, 就应该首先弄清术语表中每个术语的含义.
- 后记 (postscript)
- 一段旨在为本章所呈现的材料提供一些观点的文字.
另外, 我们建议每个学生都能参与到一个小的项目中去 (如果时间允许, 能参与更多项目当然就更好了). 一个项目的目的就是要编写一个完整的有用程序. 理想情况下, 项目由一个多人小组 (比如三个人) 共同完成 (比如在学习本书末尾章节时). 大多数人会发现做这种项目最为有趣, 并能将所有内容融会贯通.
CC 学习离不开重复. 我们的理想是每个重要的知识点都在书中至少出现两次, 并通过习题再次强调.
AA 当你完成本书的学习时, 是否能成为一名程序设计和 C++ 方面的专家呢? 当然不能! 如果做得好的话, 程序设计会是一门建立在多种专业技能上的精妙的、深刻的、需要高度技巧的艺术. 你不能指望在四个月内成为程序设计专家, 就像你不能指望花四个月时间——或半年、一年时间——就成为一名生物学专家、一名数学家、一名自然语言 (如中文、英文或丹麦文) 方面的专家, 或是一名小提琴演奏家. 但如果你认真地学完了这本书, 你可以期待也应该期待的是: 你已经在程序设计领域有了一个很好的开始, 已经可以写相对简单的、有用的程序, 能读更复杂的程序, 而且已经为进一步的学习打下了良好的理论和实践基础.
学习完这门入门课程后, 进一步学习的最好方法是开发一个真正能被别人使用的程序. 在完成这个项目之后或者同时 (同时可能更好) 学习一本专业水平的通用教材, 学习一本与你做的项目相关的更专业的书, 或者学习一本专注于 C++ 某个特定方面的教材 (如算法、图形学、科学计算、金融或游戏); 参考 :ref:`天鹅书参考文献`.
AA 最后, 你应该学习另一门程序设计语言. 我们认为, 如果只懂一门语言, 要成为软件领域的专家 (即使你并不是想做一名程序员) 是不可能的. 为什么呢? 因为没有哪个大型程序是用单一语言编写的. 此外, 不同语言通常在思考代码和程序构建的方式上有所不同. 其设计技术、可用的库和程序构建的方式有所差异——很多时候迥然不同. 即便两个语言的语法很相似, 这种相似通常仅体现在表面层次. 其性能、错误检测能力以及对表达内容的限制通常不同. 这与自然语言和文化的差异类似。 只知道一种语言和文化隐含着一种危险观念: 认为 "我们做事的方式" 是唯一的方式或唯一优秀的方式. 这样一来会错失很多机会, 并产生出欠佳的程序. 避免这种问题的最佳方式之一就是熟悉多种语言 (编程语言和自然语言).
我们试图帮助你学习什么? 又是如何安排学习进程的? 我们的做法是, 尽力为你提供编写高效的实用程序所需的最基本的概念、技术和工具, 包括
- 程序组织
- 调试和测试
- 类设计
- 计算
- 函数和算法设计
- 图形学 (仅介绍二维图形)
- 图形用户界面 (Graphical User Interface, GUI)
- 文件和流输入输出 (I/O)
- 内存管理
- 设计和程序设计思想
- C++ 标准库
- 软件开发策略
为了让这本书比编写它所用的笔记本电脑跟轻便, 第二版中的一些补充材料被放在了网站上 (:ref:`天鹅书网站资源`):
- 计算机、人与程序设计 (第二版第 1 章)
- 理念与历史 (第二版第 22 章)
- 文本处理 (含正则表达式匹配) (第二版第 23 章)
- 数值 (第二版第 24 章)
- 嵌入式系统程序设计 (第二版第 25 章)
- C 语言程序设计技术 (第二版第 27 章)
我们在各个章节中逐一介绍了如下程序设计技术: 过程式程序设计 (同时学习 C 语言程序)、数据抽象、面向对象程序设计和泛型程序设计. 本书的主题是 程序设计, 也就是表达代码意图所需的思想、技术和工具. C++ 语言是我们的主要工具, 因此我们比较详细地描述了很多 C++ 语言的特性. 但请记住, C++ 只是一种工具, 而不是本书的主题. 本书是 "用 C++ 语言进行程序设计", 而不是 "C++ 和一点程序设计理论".
我们介绍的每个主题都至少出于两个目的: 提出一种技术、概念或原理, 介绍一个实用的语言特性或库特性. 例如, 我们用一个二维图形绘制系统的接口展示如何使用类和继承. 这使我们节省了篇幅 (也节省了你的时间), 并且还强调了程序设计不只是简单地将代码拼装起来以尽快地得到一个结果. C++ 标准库是这种 "双重作用" 例子的主要来源, 其中很多主题甚至具有三重作用. 例如, 我们会介绍标准库中的 :cpp:`vector`, 用它来展示一些广泛使用的设计技术, 并展示很多用来实现 :cpp:`vector` 的程序设计技术. 我们的一个目标是向你展示一些主要的标准库功能是如何实现的, 以及它们如何映射到硬件上. 我们坚持认为一个工匠必须了解他的工具, 而不是仅仅把工具当作 "有魔法的东西".
对于一个程序员来说, 总是会对某些主题比对其他主题更感兴趣. 但是, 我们建议你不要预先判断你需要什么 (你怎么知道你将来会需要什么呢?), 至少每一章都要浏览一下. 如果你学习本书是作为一门课程的一部分, 你的老师会指导你如何选择学习内容.
CC 我们的教学方法可以描述为 "深度优先", 同时也是 "具体优先" 和 "基于概念". 首先, 我们快速地 (好吧, 是相对快速地, 从第 1 章到第 9 章) 将一些编写小的实用程序所需的技巧组装给你. 在这期间, 我们还简明扼要地提出很多工具和技术. 我们着重于简单具体的代码实例, 因为相对于抽象概念, 人们能更快领会具体实例, 这就是多数人的学习方法. 在最初阶段, 你不应期望理解每个小的细节. 特别是, 你会发现对刚刚还工作得好好的程序稍加改动, 便会呈现出 "神秘" 的效果. 尽管如此, 你还是要尝试一下! 还有, 请完成我们提供的简单练习和习题. 请记住, 在学习初期你只是没有掌握足够的概念和技巧来准确判断什么是简单的, 什么是复杂的. 请等待一些惊奇的事情发生, 并从中学习吧.
AA 我们会快速通过上段所述的初始阶段——我们想尽可能快地让你进入能编写有趣程序的阶段. 有些人可能会质疑, "我们的进展应该慢些、谨慎些, 我们应该先学会走, 再学跑!" 但是你见过小孩学习走路吗? 实际上小孩在学会平稳地慢慢走路之前就自己开始尝试跑了. 与之相似, 你可以先勇猛向前, 偶尔摔一跤, 从中获得编程的感觉, 然后再慢下来, 获得必要的精确控制能力和准确的理解. 你必须在学会走之前就开始跑!
XX 你不要投入大量精力试图学习一些语言或技术细节的所有相关内容. 例如, 你可以熟记所有 C++ 的内置类型及其使用规则. 你当然可以这么做, 而且这么做会使你觉得自己很博学. 但是, 这不会使你成为一名程序员. 如果你学习中略过一些细节, 将来可能偶尔会因为缺少相关知识而被 "灼伤", 但这是获取编写好程序所需的完整知识结构的最快途径. 注意, 我们的这种方法本质上就是小孩学习其母语的方法, 也是教授外语的最有效方法. 有时你不可避免地被难题困住, 我们鼓励你向授课老师、朋友、同事、指导教师等寻求帮助. 请放心, 在前面这些章节中, 所有内容本质上都不困难. 但是, 很多内容是你所不熟悉的, 因此最初可能会感觉有点难.
随后, 我们介绍一些入门技巧来拓宽你的知识. 我们通过实例和习题来强化你的理解, 为你提供一个程序设计的概念基础.
AA 我们非常强调思想和原理. 思想能指导你求解实际问题——可以帮助你知道在什么情况下问题求解方案是好的、合理的. 你还应该理解这些思想背后的原理, 从而理解为什么要接受这些思想, 为什么遵循这些思想会对你和使用你的代码的用户有帮助. 没有人会满意 "因为事情就是如此" 这样的解释. 更为重要的是, 如果真正理解了思想和原理, 你就能将自己已知的知识推广到新的情况; 就能用新的方法将思想和工具结合来解决新的问题. 知其所以然是学会程序设计技巧所必需的. 相反, 仅仅不求甚解地记住大量规则和语言特性有很大局限, 是错误之源, 是在浪费时间. 我们认为你的时间很珍贵, 尽量不要浪费它.
我们把很多 C++ 语言层面的技术细节驱除到了其他地方, 大多数放在了网站上 (:ref:`天鹅书网站资源`). 我们假定你会主动查找需要的信息. 要学会用本书的索引和目录. 不要忘了你编译器的在线帮助文档. 但要记住, 要对所有互联网资源保持足够的怀疑, 直至你有足够的理由相信它们. 因为很多看起来很权威的网站实际上是由程序设计新手或者想要出售什么东西的人建立的. 而另外一些网站的内容完全过时了. 我们在支持网站 https://www.stroustrup.com/programming.html 上列出了一些网站链接和信息 (译注: 我提供的见于 :doc:`/searching_method/main` 和 :ref:`学习大纲_常用网站资源`).
请不要过于急切地期盼 "实际的" 例子. 我们理想的实例都是能直接说明一种语言特性、一个概念或者一种技术的简短代码. 很多现实世界中的实例比我们给出的实例要凌乱很多, 而且不过是我们所展示内容的组合. 包含数十万行代码的成功商业程序正是基于我们用几个 50 行规模的程序所展示出来的技术. 理解现实世界程序的最快途径, 就是深入掌握基础知识.
我们不会用 "涉及乖巧动物的可爱风格" 来阐述我们的观点. 我们假定你的目标是编写供他人使用的实用程序. 因此书中给出的实例要么是用来说明语言特性, 要么是从实际应用中提取出来的. 我们的叙述风格都是用专业人员对 (将来的) 专业人员的那种口气.
C++ 建立在两个支柱上:
- 能够高效直接地访问机器资源
- 它使得 C++ 能高效地进行底层而接近机器的程序设计, 而这在许多应用领域是必不可少的.
- 强大的 (零开销 (zero-overhead)) 抽象机制
- 它通过提供高层次程序设计所需的优雅、灵活、类型和资源安全而又保持高效的机制, 使得摆脱易于出错的低层次程序设计成为可能.
本书涵盖了两种程序设计层次. 我们用高层次抽象的实现作为示例, 来介绍低层次的语言特性和程序设计技术. 我们的目标是总是尽可能编写高层次的代码. 但这往往需要先用低层次的机制和技术构建出一个基础. 我们的目标是让你掌握这两种程序设计层次.
数以万计的大一新生在使用本书的前两个版本学习程序设计之前, 从未接触过哪怕一行代码. 他们中大多数都成功了, 因此你也可以做到.
你不必将本书作为课程的一部分来阅读. 本书被广泛用于自学. 然而, 无论你是通过课程学习还是自学程序设计, 尝试与他人合作. 程序设计被曲解为一项孤独的活动. 但对于大多数人, 当他们加入一个拥有共同目标的团体时, 会工作得更好, 学习得更快. 与朋友一起学习并讨论问题并不是作弊! 这是最有效率——也是最愉快——的进步方式. 不说别的, 与朋友合作迫使你清楚表达你的想法, 而这几乎是测试你理解情况和确保你能牢记的最有效途径. 你不必亲自去探求每个晦涩用语和编程环境问题的答案. 然而, 请不要欺骗你自己, 偷懒不去做简单练习和一定量的习题 (即使没有老师强迫你做). 记住: 程序设计 (相比于其他) 是一项你必须通过实践来掌握的实用技能.
大多数学生——尤其是那些考虑周到的优秀学生——都会经历质疑自己辛勤付出是否值得的时刻. 当 (不是 "如果") 这种情况发生在你身上时, 休息一下, 重读本章读者须知, 查看网站上 (:ref:`天鹅书网站资源`) 发布的 "计算机、人与程序设计" 和 "理念与历史" 章节. 在那里, 我试图阐明我感兴趣于程序设计的原因, 以及我为何认为它是为世界做出积极贡献的关键工具.
请别太心急. 学习任何重要的新技能都需要时间.
这本书的主要目的在于帮助你用代码表达你的想法, 而非教你如何获取这些想法. 在这个过程中, 我们提供了许多例子来解释我们是如何解决某些问题的, 通常是通过对问题进行分析, 然后逐步优化解决方案. 我们认为程序设计本身就是一种解决问题的形式: 只有完全理解一个问题及其解决方案, 你才能为它编写出正确的程序; 同样, 只有通过构建和测试程序, 你才能确信你的理解是全面的. 因此, 程序设计本质上是为了增进理解而进行的一种努力. 然而, 我们试图通过实例来演示这一点, 而不是通过 "传教布道" 或展示对问题解决方案的详细描述
CC 不, 本书不是在教传统的计算机科学 101 课程. 这是一本关于如何构建可使用软件的书. 因此, 它省略了许多计算机科学学生在传统课程中常常接触到的内容 (图灵完备性、状态机、离散数学、形式文法等). 甚至, 基于学生从幼儿园起就以不同方式使用过计算机的假设, 硬件也被本书所忽略. 本书甚至不尝试提及大多数重要的计算机科学主题. 它关注程序设计 (或更广泛地说, 关注如何开发程序), 因此相比许多传统课程, 它更深入地探讨了更少的主题. 本书力求仅将一件事做到极致, 而计算机科学并非单一课程所能涵盖的. 如果本书/课程被用作计算机科学、计算机工程、电气工程 (我们的首批学生中有很多是电气工程专业)、信息科学或其他涉及程序设计的专业的一部分, 我们希望它与其他课程一起讲授, 作为整体介绍的一部分.
许多学生都希望了解为什么要教授这些科目,以及为什么要以这种方式教授这些科目. 因此请在教学过程中向学生传达我的教学理念、总体方法等. 此外, 为了激励学生, 请简要展示一些 C++ 广泛应用的领域和应用程序, 如航空航天、医学、游戏、动画、汽车、金融和科学计算.
C++ 由 ISO 标准定义. 首个 ISO C++ 标准于 1998 年获得批准, 因而该版本 C++ 被称为 C++98. 本书这一版的代码采用当代 C++ (Contemporary C++), 即 C++20 (加上一些 C++23 的内容). 如果你的编译器不支持 C++20 [C++20], 请更新至最新版本编译器. 你可以从各种供应商处下载优秀的现代 C++ 编译器, 请参见 https://www.stroustrup.com/compilers.html. 使用较早且支持性较差的语言版本学习程序设计可能会遇到不必要的困难. (译注: :ref:`我的 C++ 环境配置教程 <环境配置>`.)
另一方面, 你看处于只能使用 C++14 或 C++17 的环境中. 本书的大部分内容仍然适用, 但你会因缺乏 C++20 引入的特性而遇到问题:
- 模块 (:cpp:`module`) (§7.7.1)
- 使用头文件 (§7.7.2) 替代模块. 特别是, 使用 :cpp:`#include "PPPheaders.h"` 来编译我们的示例和你的习题, 而不是 :cpp:`#include "PPP.h"` (:ref:`天鹅书支持库`).
- 范围 (:cpp:`range`) (§20.7)
- 使用显式迭代器, 而不是使用范围. 例如, 使用 :cpp:`sort(v.begin(), v.end())`, 而不是 :cpp:`ranges::sort(v)`. 如果/当这变得乏味, 你可以为你喜欢的算法编写自己的范围版本 (§21.1).
- :cpp:`span` (§16.4.1)
- 重新使用古老的 "指针和大小" 技巧. 例如, 使用 :cpp:`void f(int* p, int n);` 而不是 :cpp:`void f(span<int> s)`, 然后根据需要自己进行范围检查.
- 概念 (:cpp:`concept`) (§18.1.3)
- 使用无修饰的 :cpp:`template <typename T>` 并期盼一切顺利. 哪怕这样的代码中仅有简单错误, 也会产生出非常可怕的错误信息.
编写运行于多种平台的 C++ 程序是很常见的情况. 一些重要的 C++ 应用甚至运行于我们闻所未闻的平台! 我们认为在各种及其架构和操作系统能使用 C++ 是非常重要的特性. 本质上, 本书的每个例子都不仅是 ISO 标准 C++ 程序, 还是可移植的. 所谓移植性, 我们指的是除了假设存在一个符合最新标准的 C++ 实现之外, 我们不对计算机、操作系统以及编译器做其他任何假设. 除非特别之处, 本书的代码都能运行于任何一种 C++ 实现, 并且确实已经在多种计算机平台和操作系统上测试通过了.
不同系统编译、链接和运行 C++ 程序的细节各不相同, 此外, 大多数系统都提供了多个编译器和工具供选择. 本书并不包括解释众多且常常变化的工具集. 我们可能会在本书的支持网站 (:ref:`天鹅书支持库`) 上添加一些这类的信息.
如果你在使用任何一种流行的但相对复杂的 IDE (集成开发环境, Integrated Development Environment) 时遇到了困难, 我们建议你尝试命令行工作方式; 它极其简单. 例如, 下面给出的是在 Unix 或 Linux 平台用 GNU C++ 编译器编译、链接和运行一个包含两个源文件 my_file1.cpp 和 my_file2.cpp 的简单程序所需的全部命令:
c++ -o my_program my_file1.cpp my_file2.cpp
./my_program
是的, 这真的就是全部.
另一种入门方法是使用构建系统, 例如 CMake (:ref:`天鹅书支持库`). 然而, 这条路径最好由有经验的人员来指导最开始的步骤.
(译注: :ref:`我的 C++ 环境配置教程 <环境配置>` 中直接为天鹅书第二版、第三版提供了支持.)
除非用于说明错误, 本书中的代码都是类型安全的 (对象 (object) 仅根据其定义 (definition) 被使用). 我们遵循《C++ 核心准则》(The C++ Core Guidelines) 中的规则来简化程序设计并消除常见错误. 你可以在网上找到《C++ 核心准则》[CG], 而且在需要确保遵循准则时使用规则检查器. (译注: :ref:`我的 C++ 环境配置教程 <环境配置>` 默认配置了规则检查器 clang-tidy 并开启了一些不影响初学者学习的常见检查.)
我们不推荐你在初学阶段深究这部分内容, 但它让你放心地知道, 本书推荐的风格和技术都有工业支持. 一旦你熟悉了 C++ 并了解了潜在的错误 (比如在读完 16 章之后), 我们建议你阅读《C++ 核心准则》的介绍并尝试使用一个《C++ 核心准则》检查器, 看看检查器是如何在代码运行之前消除其中的错误.
我从 1979 年末开始设计并实现 C++, 大约六个月后为我的第一个用户提供了支持. 初始功能包括带有构造函数和析构函数的类 (§8.4.2, §15.5), 以及函数参数声明 (§3.5.2). 起初, 该语言被称为 C with Classes, 但为了避免与 C 混淆, 它在1985 年被重命名为 C++.
C++ 的基本理念是将 C 语言高效利用硬件的能力 (如设备驱动、内存管理器、进程调度器等) [K&R] 与 Simula 组织代码的机制 (特别是类和派生类) [Simula] 结合起来. 我需要它来完成一个项目, 即构建一个分布式 Unix 系统. 如果成功, 它可能会成为首个 Unix 集群, 但对 C++ 的开发 "分散" 了我的注意力, 使我没能专注于这一目标.
1985 年, 首个 C++ 编译器和基础库的商业化实现正式发布. 我编写了其中大部分代码及大部分文档. 首部关于 C++ 的书籍《C++程序设计语言》(The C++ Programming Language) [TC++PL] 也同期出版. 当时, 该语言支持被称为数据抽象 (data abstraction) 和面向对象 (object-oriented) 程序设计 (§12.3, §12.5). 此外, 它对泛型程序设计 (generic programming) 提供了基础性支持 (§21.1.2).
20 世纪 80 年代末, 我致力于设计异常 (exception) (§4.6) 和模板 (template) (第 18 章). 模板旨在沿袭 Alex Stepanov 的研究 [AS,2009], 支持泛型程序设计.
1989 年, 几家大型企业认定我们需要为 C++ 制定 ISO 标准. 与 Margaret Ellis 一起, 我撰写了成为 C++ 标准化基石的文档——《ARM》(The Annotated C++ Reference Manual) [ARM]. 首个 ISO 标准于 1998 年由 20 个国家批准, 称为 C++98. 在之后十年时间里, C++98 支撑了 C++ 使用的迅猛增长, 并为后续发展提供了大量宝贵反馈. 除语言外, 标准还规定了一个大规模的标准库. 在 C++98 中, 最重要的标准库组件是 STL, 其提供了迭代器(§19.3.2)、容器 (例如 :cpp:`vector` (§3.6) 和 :cpp:`map` (§20.2)) 和算法 (§21).
C++11 是一次重大升级, 它为编译时计算 (§3.3.1) 添加了改进设施, 加入了 lambdas (§13.3.3, §21.2.3), 并正式支持了并发. 并发在 C++ 早期就有应用, 但这个既有趣又重要的话题已超出本书的讨论范围. 学完本书后你可以参考 [AW,2019]. C++11 标准库新增了许多使用组件, 特别是随机数生成 (§4.7.5) 和资源管理指针 (:cpp:`unique_ptr` (§18.5.2) 和 :cpp:`shared_ptr` (§18.5.3)).
C++14 和 C++17 增加了许多实用的特性, 但并未增加对全新程序设计风格的支持.
C++20 [C++20] 是 C++ 的一次重大改进, 其重要性与 C++11 相当, 并且接近于实现我在 1994 年《C++的设计与演化》(The Design and Evolution of C++) [DnE] 中所阐述的, 对 C++ 的理想. 它进行了许多扩展, 包括添加了模块 (module) (§7.7.1)、概念 (concept) (§18.1.3)、协程 (coroutine) (超出本书范围) 以及范围 (range) (§20.7).
这些改动在几十年来逐渐演进, 并且高度重视向后兼容性 (backwards compability) (译注: 向后兼容性指新版本仍能直接使用旧版本代码). 我有一些上世纪 80 年代的小程序至今仍能正常运行. 如果旧的代码无法正常编译或运行, 原因通常是操作系统或第三方库的变更. 这提供了一定程度的稳定性,对于那些维护使用了几十年的软件的组织来说, 这是 C++ 的一大特色.
关于 C++ 设计与演化的更全面讨论, 请参考《C++ 的设计与演化》[DnE] 以及我的三篇 ACM 程序设计历史会议 (ACM History of Programming Conference) 论文 [HOPL-2] [HOPL-3] [HOPL-4]. 不过, 这些不是为初学者编写的.
本书中的所有代码均为 ISO 标准 C++ 代码. 要开始编译并运行示例, 请在代码开头添加以下两行:
import std;
using namespace std;
这使得标准库可用.
不幸的是, 标准并未保证对 :cpp:`vector` 等容器进行范围检查 (range checking), 而大多数实现默认情况下也不强制执行这样的检查. 通常, 这样的强制检查必须通过启用因编译器而异的选项来开启. 我们认为范围检查对于简化学习过程并减少挫败感至关重要. 因此, 我们提供了一个名为 :cpp:`PPP_support` 的模块, 该模块提供了一个保证对下标操作进行范围检查的 C++ 标准库版本 (参见 https://www.stroustrup.com/programming.html). 因此, 请勿直接使用 :cpp:`std` 模块, 而是改为使用:
#include "PPP.h"
我们还提供了与 :cpp:`"PPP.h"` 类似的 :cpp:`"PPPheaders.h"`, 供无法使用具有良好模块支持的编译器的人使用. 该版本提供的 C++ 标准库内容更少, 且编译速度更慢.
有些人对我们为本书第一版和第二版使用支持头文件的做法 (译注: 如这里用 :cpp:`#include "PPP.h"` 而不是用 :cpp:`import std;`) 作出评论, 称 "使用非标准的头文件不是实际的 C++". 然而这是合理的, 因为这些支持头文件的内容 100% 符合 ISO C++ 标准, 并且不会改变正确程序的含义. 我们认为, 我们的支持库能够很好地帮助你避免不可移植的代码和意外行为, 这一点非常重要. 此外, 编写出能够更容易地支持高质量高效代码的库是 C++ 的主要用途之一. :cpp:`PPP_support` 模块只是其中一个简单的例子.
AA 如果你不能下载本书的支持库, 或者在编译时遇到困难, 可以直接使用标准库, 但要设法找到启用范围检查的方法. 所有主要 C++ 实现都有这样的选项, 但要设法找到并启用它并非易事. 对于所有环境配置问题, 最佳做法是向有经验的人寻求建议.
此外, 当你阅读到第 10 章并需要运行图形学 (Graphics) 和图形用户界面 (Graphical User Interface, GUI) 的代码时, 你需要安装 Qt graphics/GUI 系统以及为本书专门设计的接口库. 参见 印刷错误 和 https://www.stroustrup.com/programming.html.
(译注: :ref:`我的 C++ 环境配置教程 <环境配置>` 默认配置了检查, 并直接支持天鹅书第二版、第三版使用的教学库和 Qt.)
网上关于 C++ 的资料浩如烟海, 包括文本和视频. 遗憾的是, 这些资料的质量参差不齐, 许多针对高水平用户, 许多已经过时. 因此, 使用时请小心谨慎, 并保持足够的怀疑态度.
AA 本书的支持网站是 https://www.stroustrup.com/programming.html. 在那里, 你可以找到
- :cpp:`PPP_support` 模块源代码 (:ref:`天鹅书支持库`).
- :cpp:`PPP.h` 和 :cpp:`PPPheaders.h` 头文件 (:ref:`天鹅书支持库`).
- 一些本书支持库的安装指南.
- 一些代码示例.
- 勘误表.
- 天鹅书第二版 (《Programming: Principles and Practice Using C++》第二版) [PPP2] 中为了节省篇幅和因为有其他资源可用而被删减的章节. 这些章节可在 https://www.stroustrup.com/programming.html 获取, 并在天鹅书第三版文本中以如下形式引用: PPP2.Ch22 或 PPP2.§22.1.2.
其他网络资源:
- 我的网站 https://www.stroustrup.com 包含大量与 C++ 相关的资料.
- C++ 基金会的网站 https://www.isocpp.org 提供了各种有用且有趣的信息, 其中有很多与标准化相关, 但也有大量文章和新闻.
- 我推荐用 https://cppreference.com 作为在线的参考手册. 我自己每天都用它来查阅语言和标准库中晦涩的细节. 但我不推荐将它当成教程使用.
- 主要的 C++ 实现者, 如 Clang、GCC 和 Microsoft, 都提供了其产品良好版本的免费下载 (https://www.stroustrup.com/compilers.html). 所有这些产品均具备强制执行下标范围检查的选项.
- 有很多网站提供 (免费) 在线 C++ 编译服务, 如 Compiler Explorer. 这些网站易于使用, 非常适合测试小的示例和查看不同编译器及其不同版本如何处理源代码.
- 有关如何使用当代 C++ (Contemporary C++) 的指南, 参见 C++ 核心准则 [CG] 和 它的小型支持库. 除非用于说明错误, 本书中的代码均遵循核心准则.
- 对于第 10 章到第 14 章的内容, 我们使用 Qt 作为图形学和 GUI 代码的基础.
你可能有理由问: "你是谁, 凭什么认为能帮助我学习程序设计?" 以下是我预制的个人简介:
Bjarne Stroustrup 是 C++ 的设计者和最初实现者, 也是《C++程序设计语言(第4版)》(The C++ Programming Language (4th Edition))、《C++之旅(第3版)》(A Tour of C++ (3rd Edition))、《程序设计:使用C++的原理与实践(第3版)》(Programming: Principles and Practice Using C++ (3rd Edition)) 以及许多流行和学术出版物的作者. 他目前在纽约市的哥伦比亚大学 (Columbia University) 担任计算机科学教授. Stroustrup 博士是美国国家工程院 (the US National Academy of Engineering) 成员, 也是 IEEE、ACM 和计算机历史博物馆 (CHM) 会士 (fellow). 他荣获了 2018 年 Charles Stark Draper 奖, IEEE 计算机协会 2018 年的计算机先锋奖以及 2017 年英国工程技术学会 (IET) 法拉第奖章. 加入哥伦比亚大学之前, 他是得克萨斯农工大学 (Texas A&M University) 的特聘教授以及摩根士丹利 (Morgan Stanley) 的技术院士和董事总经理. 他的许多重要工作都是在贝尔实验室完成的. 他的研究兴趣包括分布式系统、设计、程序设计技术、软件开发工具和编程语言. 为使 C++ 成为现实世界软件开发的稳定且不断更新的基础, 他在 ISO C++ 标准制定工作中担任了超过 30 年的领导角色. 他持有奥胡斯大学 (Aarhus University) 数学硕士学位, 并在该校计算机科学系担任荣誉教授; 他还持有剑桥大学 (Cambridge University) 计算机科学博士学位, 并是丘吉尔学院 (Churchill College) 的荣誉院士. 他还是马德里卡洛斯三世大学 (Universidad Carlos III de Madrid) 的荣誉博士. https://www.stroustrup.com.
换句话说, 我拥有丰富的工业和学术经验.
我曾使用本书的早期版本教授过数千名大一新生, 其中许多人之前从未写过一行代码. 除此之外, 我还教授过从本科生到经验丰富的开发人员和科学家等各个层次的人群. 我现在在哥伦比亚大学教授本科生和研究生的最后一年课程.
我的确有工作之外的生活. 我已婚, 有两个孩子和五个孙子孙女. 我读很多书, 包括历史、科幻小说、犯罪小说和时事. 我喜欢各种音乐, 包括古典音乐、经典摇滚、蓝调和乡村音乐. 与朋友一起品尝美食是必不可少的, 而且我喜欢游览世界各地有趣的地方. 为了能够享受美食, 我坚持跑步.
要了解更多生平信息, 请访问 https://www.stroustrup.com/bio.html.
下面列出了本章提及的参考文献, 以及可能对你有用的一些文献.
- [ARM]
- Ellis and B. Stroustrup: The Annotated C++ Reference Manual. Addison-Wesley. 1990. ISBN 0-201-51459-1.
- [AS,2009]
- Alexander Stepanov and Paul McJones: Elements of Programming. Addison-Wesley. 2009. ISBN 978-0-321-63537-2.
- [AW,2019]
- Anthony Williams: C++ Concurrency in Action: Practical Multithreading (Second edition). Manning Publishing. 2019. ISBN 978-1617294693.
- [BS,2022]
- Stroustrup: A Tour of C++ (3rd edition). Addison-Wesley, 2022. ISBN 978-0136816485.
- [CG]
- Stroustrup and H. Sutter: C++ Core Guidelines. https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md.
- [C++20]
- Richard Smith (editor): The C++ Standard. ISO/IEC 14882:2020.
- [DnE]
- Stroustrup: The Design and Evolution of C++. Addison-Wesley, 1994. ISBN 0201543303.
- [HOPL-2]
- Stroustrup: A History of C++: 1979–1991. Proc. ACM History of Programming Languages Conference (HOPL-2). ACM Sigplan Notices. Vol 28, No 3. 1993.
- [HOPL-3]
- Stroustrup: Evolving a language in and for the real world: C++ 1991-2006. ACM HOPL-III. June 2007.
- [HOPL-4]
- Stroustrup: Thriving in a crowded and changing world: C++ 2006-2020. ACM/SIGPLAN History of Programming Languages conference, HOPL-IV. June 2021.
- [K&R]
- Brian W. Kernighan and Dennis M. Ritchie: The C Programming Language. Prentice-Hall. 1978. ISBN 978-0131101630.
- [Simula]
- Graham Birtwistle, Ole-Johan Dahl, Bjørn Myhrhaug, and Kristen Nygaard: SIMULA BEGIN. Studentlitteratur. 1979. ISBN 91-44-06212-5.
- [TC++PL]
- Stroustrup: The C++ Programming Language (Fourth Edition). Addison-Wesley, 2013. ISBN 0321563840.
每章最后都附有一个简短的 "后记", 试图对该章节所呈现的内容提供一些看法. 我们这样做是因为认识到这些内容可能——而且通常是——令人望而生畏的, 而只有在完成习题, 阅读后续章节 (应用本章中的概念) 并回顾本章之后, 才能完全理解. 不要慌! 放轻松; 会有这种情况是很自然的, 而且在我们预料之中. 你不会在一天内就成为专家, 但通过学习本书, 你可以成为一名相当称职的程序员. 在此过程中, 你会遇到许多信息, 众多示例和诸多技术, 这些都曾令成千上万的程序员感到振奋和有趣.