图书前言

中文版推荐序一

对于大型软件,要想降低系统复杂度、使软件的各个组件可以独立演化,就需要在各个组件之间提供良好的编程接口——这就是所谓的 API ,其设计好坏是决定软件能否做到高内聚、低耦合的关键因素。对于平台、程序库和框架(不管是否开源),这会直接影响软件生态能否蓬勃发展。这本书全面总结了API 设计的最佳实践,它的出版令我倍感欣喜。

你可能会想,我只是一个普通的 C++ 程序员,也需要学习 API 设计吗?答案通常是肯定的。借用本书作者的话:“如果你编写的 C++ 代码被其他工程师所依赖,你就可以称作 API 设计师,而本书就是为你编写的。”如果 API 设计得不好,使用者(可能是你身边的同事)上手会更困难,他们的代码会与你的代码产生不必要的耦合,影响整体的可维护性。为了不让你的伙伴或客户感到痛苦,任何需要在代码上与他人合作的工程师都需要设计良好的 API。

在人工智能大行其道的今天,API 设计变得分外重要,因为目前的大语言模型在实现层面往往已经做得相当不错了,但在接口设计上,通常还是缺乏品位和远见。一个软件工程师如果不想失业的话,就需要在系统设计上多动脑筋,API 设计就是其中的重要一环。好的 API 设计会把接口和实现分开,使得实现的修改几乎不影响调用侧代码。这样,人和大语言模型都不必关心实现细节,从而同时降低人的认知负担和模型的上下文消耗,使模型修改代码时更加轻松——毕竟,大语言模型与人是不同的,它通常有一个硬上下文限制,一旦到了这个限制,其能力就会急剧退化,其后果远比人出现判断偏差时严重。

本书以 C++ 为基准语言,但书里谈到的原则对各种语言的开发者同样有启发。尤其值得一提的是,书里对 C、Objective-C、Swift、Python、Ruby 这些经常与 C++ 有交互的语言都进行了讨论,这样可以满足很多实际使用场景的需要。由此可见,这本书的实用性相当高,它并非泛泛地讨论一些原则,让读者不知道从何入手。

如果说我对这本书有什么不满的话,最主要的地方就在于这本书不够“新”,对此,我需要略加说明。本书原著第1版出版于 2011 年,第2版出版于 2024 年,且在第2版中更新了 C++ 11/14/17/20/23 的内容。这些更新当然不错,但在某些细节方面存在一定的滞后。此外,有些最佳实践与最新的 C++ Core Guidelines有所冲突(如核心指南的 C.35 条款)。这些需要读者在阅读时有所甄别。不管是多么权威的书,读者在阅读过程中都应该批判性地进行学习,这也是对任何一本技术书籍应有的态度。

吴咏炜

奇点智能研究院首席技术咨询师

《C++ 实战:核心技术与最佳实践》作者

《C++ Core Guidelines 解析》共同译者

中文版推荐序二

在AI大行其道的时代里,作为真人程序员,我们应该干点什么呢?

在很多AI信徒的眼里,AI是无所不能的,包括翻译和作序。坦率说,在我一字一句写这个序之前,我确实让AI写了一版,但看了之后,我明白了什么叫“AI味道”。每一句话都说得很对,每一句话都很通顺,甚至也有几分文采,但是我嗤之以鼻。因为满屏幕都是陈词滥调,读了一段就知道后面一段要说什么,读了两段,就再也不想读下去了。用两个字概括就是“乏味”。

文贵出新,唯有新,才能引人入胜,让人不忍释卷;唯有新,才能笔落惊风雨,诗成泣鬼神。

在我看来,软件活动也是一种创作,就像作家创作文学作品,也像建筑师创作伟大的建筑。我的意思是,做软件也要不断创新,要为了创新而苦思冥想,夜不能寐。反过来说,不要简单地堆砌代码,不要只做代码的搬运工。

或者说,一个有理想的程序员不应该只会搬运AI产生的代码。那应该做什么呢?这本书指出的方向是设计,进一步说是接口设计。

当然设计也有照搬和创造两种,这本书要传授的当然是创造性的设计。

接口是软件之间的契约,它代表着软件的关键基因,也是支撑软件大厦的骨架。很多时候,代码重新写了,但是接口没有变,就像房子内部重新装修了一番,但是建筑的框架没有动。

在1990年的夏天,一个年轻人被一本书吸引了。几乎一整个夏季,这个年轻人都在看那本书,那本书仿佛长在了他的床上。书的名字叫《操作系统:设计与实现》,书的作者是阿姆斯特丹大学的安德鲁•塔南鲍姆(Andrew Tanenbaum)教授。年轻人一边读书中关于UNIX系统原理的描述,一边看书中介绍的MINIX代码,他被UNIX的简洁、强大、完美所深深打动,他被震撼了,对其中所包含的匠心和智慧如痴如醉。这种热爱和陶醉在十几年后他回忆这段经历时仍没有丝毫消减。而最打动他的就是UNIX的文件接口,也就是我们今天所熟知的“一切皆文件”思想,以及可以操作一切的那几个文件函数:open、read、write和close。

这个年轻人名叫林纳斯,他为了实践自己的认知,亲自动手写了个操作系统,这个操作系统最初实现的一批接口函数就有open、read、write和close。这个操作系统的名字大家都知道。这套接口诞生在著名的贝尔实验室,设计者们在创作出这套接口时,也是激动不已……

为了讲这个故事,我宁愿花一个晚上手写每一句话。希望大家读了之后,能够理解好的软件和好的接口都需要创作,不是简单的复制。

张银奎

格蠹科技创始人,《软件简史》作者

中文版推荐序三

API设计不易。变与恒、藏与露、虚与实、紧与松等分寸难以量化,更难以把控。历史证明,大团队和高资源投入本身并不能保证交付健壮而优雅的软件产品,同时,不断有小团队乃至个人开发者借革命性技术带来的生产力飞跃,独领风骚,做出改变世界的软件杰作。留意OpenClaw作者Peter Steinberger等弄潮儿,其过人之处往往在于API层面的超常敏锐和深厚功力。

本书以API为主轴,从基本概念、原则、设计风格等出发,深入语言底层特征,回答了性能、版本、测试等“必答题”,并扩展到库、插件、脚本绑定及生态等更广的范围,涉及一线开发实践的诸多方面。难得的是,这样一本容易写“虚”的书读来并不让人觉得空,而是结合作者在3D引擎等系统软件开发领域的实战经验,将观念和原则落到了C++开发实处。

本书前两章讨论的API概念和特质是软件开发的永久话题,API缩写的两种理解(是“application programming interface”还是“abstract programming interface”),“最糟糕的API就是根本没有API”,“首先要将每一个软件问题视为一个API设计问题”……相信这些论述能引起许多程序员朋友的共鸣。由于C++语言对版本兼容的极致追求,C++相关的内容将具有长期价值,许多细节会让人想起海勒姆定律发挥作用的那些微妙时刻。由于作者的独特背景,第13章中关于苹果平台生态的内容具有特别价值。第14~15章中关于脚本化和可扩展性的内容会给嵌入式等传统纯C/C++同行不少启发,随着AI智能体的兴起,“脚本语言为骨为皮,系统语言为核心为引擎”的构建形式和持续演化、扩展的软件形态正成为主流。对于有经验的读者来说,本书中点到为止和有意略过的内容,也正是将API设计思想付诸实践的范例。

严复先生在《英文汉诂》中说:“昔英博士约翰孙有云,氏无论古今也,但使其国有独擅之学术,有可喜之文辞,而他种之民有求其学术,赏其文辞者,是非习其文字语言必不可。文字语言者,其学术文辞之价值也,夫入市求物,不具价者无所得也,矧文辞之精学术之宝贵者乎。”C/C++语言构建了软件工业的基石,是软件王国的“国语”。从 API 这一关键切入点深入理解C/C++ 语言、库和相关生态,正是增长“独擅”的软件抽象功力,养成敏锐软件品位的正路。软件是真实世界的抽象,也正改变着世界。从软件王国拉远我们的视线,许多事物,如译文之于原文、不同层面的商业活动之于人类社会、语言之于意识,API的影子无处不在。读者在本书所得,也许能在其他的时空带来惊喜。

我和荣华老师相识多年,他在持续交付出色软件产品的同时,组织和参与了多部C/C++经典著作的译注工作。漫漫软件征途中,本书定能帮助读者深入软件王国的辽远疆域,创造出更健壮、更优雅的软件。

杨文波

于忘知几斋

行业名家力荐

本书堪称 C++ 界的 “代码整洁之道”,它跳出了细碎的语法讲解,聚焦如何设计优雅、易维护、易扩展的接口与架构,帮你写出真正高质量的 C++ 代码。

全书从 API 设计的核心原则、经典模式,讲到现代 C++ 各版本新特性的应用,层层递进,兼具理论深度与工程实践指导,更融入了大量性能优化、并发安全与跨版本兼容的实战技巧,致力于帮你写出更安全、更健壮的 C++ 程序。

尤其值得一提的是,本书译者团队功力深厚,我与部分译者相熟,深知其过硬的开发功底,译文精准、流畅,让原著的精髓毫无损耗地传递给读者。无论你是想提升架构设计能力,还是系统学习现代 C++ 特性,这本书都是不可多得的进阶指南,值得反复品读。

程序喵,C++头部公众号“程序喵大人”主理人

作为《C++ API设计》(第1版)的译者,我深知这本著作在API设计领域的独特价值。Martin Reddy博士凭借其在皮克斯动画工作室、苹果公司等顶尖企业的实践经验,将API设计的核心理念娓娓道来,使本书成为兼具理论深度与工程实战价值的软件工程佳作。

第2版全面更新至C++23标准,新增了并发与多线程、C++与Objective-C/Swift互操作等前沿内容,并结合现代C++的发展,对接口设计理念进行了系统性的补充与完善。对于初入行业的C++工程师,本书能够帮助其建立良好的接口设计思维;对于经验丰富的系统架构师,本书同样提供了大量值得借鉴的实践经验与设计细节。

特别值得一提的是,本书第2版由长期深耕C++领域的高校教授与技术专家共同翻译,既保持了学术表达的严谨性,又兼顾工程实践中的可读性与实用性,整体译文精准、流畅,阅读体验极佳。此外,书中还提供了从传统C++98代码库向C++11、C++14、C++17、C++20以及C++23迁移的具体建议,对希望逐步升级现代C++技术栈的开发者而言,这些建议具有很高的参考价值。

本书最大的特点在于“务实”。它并不拘泥于抽象理论,而是结合大量真实项目经验,对API设计中的经典原则、常见模式与最佳实践进行了深入总结与系统梳理。如果你正在寻找一本能够真正提升C++接口设计能力的著作,那么第2版新增的现代C++内容,以及对经典API设计原则的深入阐述,都值得认真品读。

臧秀涛,开源运营专家、技术编辑

这是C++API设计领域的经典权威著作。在AI时代,大量代码已经可以自动生成,人类软件工程师是否还需要兢兢业业地学习API开发的接口规范、模块解耦、版本兼容、工程健壮性?人机如何分工合作?这本书能否让工程师真正拥有指挥AI的能力?时间会给出答案。

罗勇军,华东理工大学信息科学与工程学院副教授

《算法竞赛》《程序设计竞赛专题挑战教程》《蓝桥杯算法入门》共同作者

译 者 序

翻译初衷

关于为什么要翻译这本书,主要有以下几方面。从2016年开始,我一直在北京交通大学讲授计算机专业的“软件设计”和“操作系统”以及通信专业的“软件工程”课程。这些课程从本质上讲都旨在解决大型复杂软件领域问题,例如,软件设计面向软件的模式和风格,操作系统面向并发和并行,软件工程面向生产和维护,等等。目前,该领域已经有非常成熟的理论体系和丰富的教材。然而,据我多年的教学实践,以及我同国内外知名大学的同行的交流,这些课程内容普遍偏理论化,缺乏与具体的编程语言和开发平台的关联。这种抽象化的倾向证明了这些学科发展的先进性和完备性,却忽略了我们教育的主体——信息领域的大学生,以及我们的教育目标——软件行业的工程师。

一次机缘巧合,我有幸结识了清华大学出版社的编辑王军,和他谈及了大学计算机专业对基于流行编程平台的软件设计技术的教材和参考书的需求,他给我推荐了这本书。在阅读了样章后,我惊奇地发现这正是我多年追寻的。它几乎为我在教学中讲述的每个接口技术、模式和风格都提供了C++代码样例,而且与我所授的课程匹配度极高,好像我的教学内容是由其抽象出来的一样。我非常兴奋,暂停了手头所有的工作,一口气翻译了样章。

C++语言自1983年诞生以来,经过数十年的演进,已经成为一门极其强大但也极具挑战性的语言。其核心复杂性体现在以下几个方面。

●语言特性庞杂:C++兼具过程式、面向对象和泛型编程范式,并在C++11及之后的版本中引入了大量新特性,如lambda表达式、智能指针、并发库等,学习曲线陡峭。

●内存管理复杂:相比于能够自动进行垃圾回收的Java和Python,C++需要手动管理内存,稍有不慎,便可能导致内存泄漏或悬垂指针。

●API设计的挑战:如何在封装内部实现的同时提供简洁、高效、可扩展的接口,是C++开发者必须面对的问题。

本书概述

API Design for C++ 由Martin Reddy博士撰写。作为一名资深的软件工程师和架构师,他在Pixar、Apple等顶尖公司积累了丰富的实战经验。本书不仅涵盖了API设计的基本原则,还详细介绍了C++语言特性对API设计的影响,提供了大量代码示例和实践技巧。尤其是在第2版中,作者新增了对C++11及之后标准(C++14、C++17、C++20、C++23)的讨论,使得本书更能满足最新C++开发的需求。

本书的核心内容围绕API设计的多个维度展开,涵盖了API设计的基本原则(如封装、易用性、稳定性)、常见的设计模式(如pimpl惯用语、工厂模式、观察者模式等)、API版本管理、并发控制、性能优化、文档编写与测试等诸多方面。对于希望深入理解C++ API设计的开发者而言,本书无疑是一本不可多得的参考书。

翻译过程与感悟

9月正是高校的开学季,通常是老师们工作最繁忙的时候,而我却把几乎所有课余时间都用在了该书的翻译上。在我看来,翻译工作就等同于备课。通过分析和调试样例代码,我对软件设计课程的内容有了更加全面和深刻的认识,弄清了许多过去容易混淆或者忽视的问题。我同步更改了教案和教学内容,设计了许多课堂演示、实验和课后编程练习。结果发现,我的讲课质量显著提高,学生们和我自己都非常满意。随着翻译的进行,我掌握了许多过去只略知一二的设计模式,如pimpl惯用语和Façade等,这极大丰富了我的讲课内容。

致谢与期待

然而,在翻译和调试源代码过程中,我也发现了一些问题,并在翻译时进行了纠正。另外,由于知识和水平的局限性,特别是长期养成的个性化用语习惯,很多专业术语可能翻译得不够精准,甚至可能出现错误,恳请专家、同行及广大读者予以指正。本书的后半部分由经验丰富的软件工程师何荣华老师和陈晓伟老师共同翻译,相信他们会凭借过硬的专业背景为读者提供高质量的译文。

希望本书能成为各位开发者案头常备的参考书,也期待它能够在教学、科研及工业界发挥更大的价值。

张晋豫

于北京交通大学

序  言

我首先声明,我认为自己并不是世界级的应用程序编程接口(application programming interface,API)设计师或软件工程师。相反,我认为自己是计算机图形学和几何建模领域的专业研究人员;正是在这一行业,我第一次在皮克斯(Pixar)动画工作室见到Martin。

作为一名图形研究员,我习惯于撰写数学上复杂的论文。我还在一所著名大学接受过计算机科学专业的正式培训,并编写过不少代码。有了这样的背景,当有机会领导一群软件工程师为皮克斯开发新一代动画软件时,我想当然地认为这不会比研究更难。要知道,从定义上讲,研究是对未知事物的探索,而工程学是对已被充分理解的学科的实现。但是,我确实大错特错了。

我逐渐意识到,软件工程无疑是我遇到过的最艰巨的挑战。在经历了不堪回首的几年之后,我最终放弃,并重新回到了图形研究领域。

我无法告诉你我能从一本书(如《C++ API设计》)中受益多少。Martin吸取了我们艰难学习过程中的许多教训,并把它们融入这本见解深刻、通俗易懂的书中。Martin不是从学术界软件研究员的角度(尽管他从学术界借鉴了大量的成果和见解),而是从一线软件工程师和管理人员的角度来研究软件工程问题。他基于自身的实践经历,深刻领悟到良好软件设计的重要性,并成了良好设计含义的清晰表达者。在这本书中,他提出了实现这一目标的有效策略。

Martin不仅关注API设计,而且广泛地关注软件生命周期,这使他能够深入讨论版本控制、向后兼容性策略和分支方法等主题。

简而言之,这本书对那些创建或管理软件活动的人来说应该很有价值。它是经过反复验证的最佳实践的全面集合。

托尼·德罗斯(Tony DeRose)

皮克斯动画工作室

资深科学家和研究小组组长

作者简介

马丁•雷迪(Martin Reddy)博士是电气和电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE)的会员,亚太人工智能协会(Asia-Pacific Artificial Intelligence Association,AAIA)会员以及美国计算机学会(Association for Computing Machinery,ACM)杰出工程师。他拥有爱丁堡大学计算机科学博士学位,在软件行业有 30 多年的工作经验。他发表过40多篇专业论文并出版了两种专著,且已获得10项专利授权。他还被母校斯特拉斯克莱德大学授予“年度杰出校友”称号。

马丁是AI初创公司PullString的联合创始人兼首席技术官,负责公司的技术开发,直到2019年,该公司被苹果公司收购。在苹果公司,马丁是人工智能和机器学习(artificial intelligence and machine learning,AI/ML)部门的软件架构师,负责Siri虚拟助理主要组件的架构和API设计,该软件目前在全球10亿多台设备上运行。

在此之前,马丁博士在皮克斯(Pixar)动画工作室工作了6年,担任首席软件工程师,为工作室的内部动画系统Presto开发API和工具。在皮克斯工作期间,马丁参与了多部荣获奥斯卡金像奖和提名的影片的制作,包括《海底总动员》《超人总动员》《汽车总动员》《美食总动员》和《机器人总动员》。值得一提的是,他还是“超能先生”的发型模特。

马丁的职业生涯始于SRI国际公司,在那里,他开发了一个名为TerraVision的分布式3D地形可视化系统,并与他人共同制定了虚拟现实建模语言(VRML)和可扩展3D(X3D) ISO(国际标准化组织)的地理空间功能规范。他连续两年当选为Web3D协会理事。他的博士研究领域为“实时3D图形系统的感知调节细节”。

前  言

本书的第1版是在2011年出版的,恰好在C++11(当时称为C++0x)标准发布之前。从那时起,C++11逐步完善,并且后续的修订版本以规律的节奏出现,包括C++14、C++17、C++20和C++23。鉴于C++语言的这些变化,我希望更新本书,使其更符合当今C++工程师的需求。因此,在第2版中,我增加了一个全新的章节,专门介绍在过去十年多的时间里添加到标准中的API设计新特性。我还对全书进行了审查,以使其与这些标准的更新相适应。这包括尽可能地用C++11语法来表示所有示例代码,因为我觉得这是当今的最低标准。

在进行如此大规模的更新时,我决定添加一些新章节,以涵盖第1版中缺失的主题。这包括一个关于并发和多线程的新章节,这一主题在C++11引入了对这一重要问题的直接支持后变得更有意义。此外,由于我在苹果公司工作了几年,我将结合自身实践经验,系统阐述如何将C++代码与Objective-C和Swift集成,因为这两种语言已成为在iOS和macOS平台上编写软件的重要语言。

最后,我在整本书中添加了几个新的部分(包括“扩展知识”),以扩充原文,内容涉及SOLID原则、线程安全接口设计模式、函数式编程风格,以及如何在API名称和文档中融入包容性语言。总之,第2版对本书进行了从头到尾的重大升级和更新。希望这个新版本能为你的软件项目提供更宝贵的资源。

应用程序编程接口设计的概念

使用C++编写大型应用程序是一项复杂的、棘手的工作,而设计健壮、稳定、易于使用和耐用的可重用C++接口则更加困难。在这项工作中取得成功的最佳方法是坚持良好的API设计原则。

API向软件组件提供了一个逻辑接口,并隐藏实现该组件所需的内部详细信息。它为模块提供了一个高级抽象,并通过允许多个应用程序共享相同的功能来促进代码重用。

现代软件开发已经高度依赖API,从低级应用程序框架到数据格式API和图形用户界面(GUI)框架,皆是如此。事实上,常见的软件工程术语,如模块化开发、代码重用、组件化、动态链接库、软件框架、分布式计算和面向服务的体系结构(SOA),都意味着需要强大的API设计技能。

你可能已经知道一些流行的C和C++ API,包括C++标准库、Boost、Microsoft Windows API(Win32)、Microsoft Foundation Classes、libtiff、libpng、zlib、libxml++、OpenGL、MySQL++、Qt、wxWidgets、GTK+、KDE、SkypeKit、Intel的线程构建块、Netscape插件API和Apache模块API。此外,谷歌公司的许多开源项目和GitHub网站上的许多代码都是C++。

API用于软件开发的各个方面:从桌面应用程序到移动计算,从嵌入式系统到Web开发。例如,Mozilla Firefox Web浏览器构建在80多个动态库之上,每个库都提供一个或多个API的实现。

因此,精致且稳健的API设计是当代软件开发的一个重要方面。与标准应用程序开发相比,一个重要区别在于它对变更管理的需求更为迫切。众所周知,变化是软件开发中不可避免的因素,新的需求、功能请求和错误修复都会导致软件以最初设计时未曾预见的方式不断演变。然而,对一个被数百个最终用户应用程序共享的API的更改可能会导致重大动荡,最终可能导致API被客户弃用。因此,好的API设计的主要目标是为客户提供所需的功能,同时在发布新版本时对其代码造成最小的影响(理想情况下为零影响)。

本书的价值

如果你编写的C++代码被其他工程师所依赖,你就可以称作API设计师,而本书就是为你编写的。

接口是你编写的最重要的代码,因为接口问题的修复成本远高于实现中的错误。例如,接口更改可能需要更新使用它的所有应用程序的代码,而单纯实现的更改可以在采用新的API版本时透明且轻松地集成到客户应用程序中。用更直白的话说,设计不佳的接口会严重降低代码的长期生存能力。因此,懂得如何创建高质量的接口是一项基本的工程技能,也是本书的核心议题。

正如米奇·亨宁(Michi Henning)所指出的,API设计在今天比20年前更加重要。这是因为近年来人们设计了更多的API。这些API提供了更丰富、更复杂的功能,并被更多的最终用户应用程序共享(Henning,2009)。尽管如此,目前市场上还没有其他专门探讨C++ API设计的书籍。

值得注意的是,我并不打算使本书成为一本通用的C++ 编程指南。目前市面上已经有很多这方面的优秀书籍。本书当然会涵盖大量面向对象设计的内容,并提供许多实用的C++编程技巧。但是,本书将聚焦在C++中表示干净模块化接口的技术,因此,不会深入探讨如何实现这些接口背后的代码,例如特定的算法选择或仅限于函数体花括号内代码的最佳实践。

另外,本书将涵盖API开发的各个方面:从最初的设计到实现、测试、文档、发布、版本控制、维护和弃用。甚至还会介绍一些特定的API主题,例如脚本和插件API的创建。这些主题通常也与软件开发相关,但本书将重点讨论它们对API设计的影响,例如,在讨论测试策略时,将集中讨论自动化API测试技术,而不涉及最终用户应用程序的测试技术,如GUI测试、系统测试或手动测试。

至于我的资历,我曾领导团队开发了被多个合作机构共享的研究代码的API,开发过用于制作获奖电影的内部动画系统API,开发过被全球数百万人使用的开源客户端/服务器API,以及已部署到十亿多台设备上的Siri虚拟助理API。在所有这些不同的经历中,我多次见证了高质量API设计的必要性。因此,本书呈现了从一系列真实经验中提炼出的工业级API设计技术和策略的实用总结。

本书读者对象

虽然本书并不是C++初学者指南,但我已尽力使文本易于阅读,并清楚地解释了所有术语和行话。因此,对于已掌握C++基础知识并希望提升设计技能的新程序员,以及寻求获得新专业知识以补充现有技能的高级工程师和软件架构师来说,本书应该是有价值的。

在撰写本书的时候,我考虑了三类特定的读者群体:

(1) 在职软件工程师和架构师。正在从事特定API项目的初级和高级开发人员需要实用的建议来完成最缜密且长效的设计。

(2) 技术经理。负责开发API产品的项目经理和产品经理须对API设计的技术问题和开发过程有更深入的了解。

(3) 学生和教育工作者。计算机科学和软件工程专业的学生在学习编程的过程中,需要一本由具有大型项目实践经验的人士撰写的软件设计系统性指南。

专注于C++

尽管有许多通用的API设计方法论(这些技术同样适用于任何编程语言或环境),但最终API必须用特定的编程语言来表达。因此,有必要理解有助于设计良好API的特定语言的特性。为此,本书侧重于单一语言(C++)的API设计问题,而不是泛化内容以使其适用于所有编程语言。希望用其他编程语言(如Java或C#)开发API的读者可以从本书中获得大量通用性的见解,但本书直接面向须编写和维护API以供其他工程师使用的C++工程师。

目前,C++仍然是大型软件项目中使用最广泛的编程语言之一,尤其是对于性能关键代码,C++是最受欢迎的选择。因此,有许多不同的C和C++ API可供你在自己的应用程序中使用,其中一些之前已经列出。因此,本书聚焦于如何用C++生成良好的API,并提供丰富的源代码示例来更好地说明涉及的所有概念。这意味着我们将处理C++特定的主题,如模板、封装、继承、命名空间、运算符、常量正确性、内存管理、并发性、C++标准库和pimpl惯用法。

正如之前提到的,本书的这一版全面涵盖了从C++98到C++23的所有C++标准修订。其中每个特定修订版占用单独的一节。这样,如果你使用的是某个特定的编译器版本(比如C++17),那么你可以轻松地查看该版本标准的所有API特性,而不会被与开发环境无关的特性分散注意力。

术语及排版规范

尽管传统上术语“用户”(user)通常指使用软件应用程序的人,如Microsoft Word或Mozilla Firefox的用户,但在API设计的背景下,我将这个术语用于指代正在创建应用程序并使用API的开发人员。换句话说,本书中谈论的通常是API用户,而不是应用程序用户。在这方面,“客户”(client)一词将被用作它的同义词。请注意,“客户”一词除了指API的人类用户,还可以指必须调用API中方法的其他软件。

尽管有许多文件格式扩展名用于标识C++源文件,如.cpp、.cc、.cxx、.h、.hh和.hpp,但我将在本书中统一使用.cpp和.h。我还将“模块”和“组件”这两个术语互换使用,表示一对单独的.cpp和.h文件(除非“模块”特指C++20的新模块特性)。它们显然不等同于术语“类”,因为一个组件或模块可能包含多个类。我将使用“库”一词来指代组件的物理集合或包(即库>模块/组件>类)。

术语“方法”(method)广泛用于面向对象编程社区,但严格来说,它并不是C++术语。它最初源于Smalltalk语言。相应的C++术语是成员函数(member function),不过,一些工程师更喜欢更具体的定义——虚成员函数。但本书并不特别关注这些术语的细微差别,因此“方法”和“成员函数”将互换使用。同样,虽然术语“数据成员”是更准确的C++表达,但我将把它和术语“成员变量”视为同义词。

在排版方面,我将等宽体用于所有源代码示例。此外,我将优先使用大驼峰命名法(Upper Camel Case)来表示示例中的所有类和函数名称(CamelCase而不是camelCase或camelcase)。但是,显然,我会保留我引用的任何外部代码的大小写,例如std::for_each()。我将在数据成员前面使用m前缀(例如mMemberVar),在静态变量前面使用s前缀(例如sStaticVar)。

本书提供的源代码示例通常只是片段,不能演示完整的功能。另外,我还经常从示例代码中去掉注释。这是出于简洁和清晰的考虑。特别是,我通常会省略头文件周围的所有预处理器保护语句。其原因是,我假设读者知道应将每个C/C++头的所有内容包含在include-guard语句(#pragma once)中,并且将所有API声明包含在一致的命名空间中。换句话说,假设我提供的每个头文件都隐式地被以下代码包围:

#ifndef MY_MODULE_H

#define MY_MODULE_H

// 所需的 #include 文件...

namespace apibook {

// API 声明...

}

#endif // MY_MODULE_H

提示:

本书还将穿插介绍各种API设计技巧和关键概念。这些提示旨在帮助你快速检索需要重温的内容。如果你时间紧迫,可以简单地浏览这些提示,然后结合上下文阅读,以便更深入地了解自己最感兴趣的主题。

源代码

本书提供完整源代码示例,扫描封底二维码,即可下载并亲自尝试这些示例。它们被设计得尽可能简单,同时仍然保留实用性和示范性。我使用了跨平台CMake 构建系统,以便编译和链接示例,因此,它们应该可以在Windows、Mac OS X和UNIX操作系统上运行。

致  谢

经过我许多朋友和同事的技术审查和反馈,本书质量得到了显著提升。我非常感谢他们抽出时间阅读本书早期版本的手稿,并提供极具深度与建设性的见解和建议。感谢保罗·施特劳斯(Paul Strauss)、埃里克·格雷戈里(Eric Gregory)、理查德·霍克斯(Rycharde Hawkes)、尼克·朗(Nick Long)、詹姆斯·查尔方特(James Chalfant)、布雷特·莱文(Brett Levin)、马库斯·马尔(Marcus Marr)、吉姆·胡梅尔辛(Jim Humelsine)和杰夫·勒夫纳(Geoff Levner)。

多年来,本书早期版本的许多读者也向我发送了反馈,其中大部分都已被纳入这个版本中。我要感谢以下人士的宝贵贡献:哈维尔·埃斯特拉达(Javier Estrada)、伊万·科玛罗夫(Ivan Komarov)、丹·史密斯(Dan Smith)、亚历山德罗斯·盖泽利斯(Alexandros Gezerlis)、林七佛(QiFo Lin)、恰达什·查勒克(Çağdaş Çalık)、马库斯·盖默(Markus Geimer)、罗杰·奥尔(Roger Orr)、克里斯·邦德(Chris Bond)、菲利普·科什(Philip Koshy)、安德烈·比格利(Andrea Bigagli)、蒋志强(Jiang Zhiqiang)、威廉·索默韦切克(William Sommerwerck)、马克·琼斯(Mark Jones)、伊尔马兹·阿尔斯拉诺格鲁(Yilmaz Arslanoglu)、费尔南多·罗森布利特(Fernando Rozenblit)、索伦·斯普洛西格(Sören Sprößig)和查尔斯·加洛德(Charles Garraud)。

我对良好API设计的热情是通过与许多杰出的软件工程师和管理人员合作而培养起来的。在不同组织的工作历程中,我接触到各种设计观点、软件开发哲学和解决问题的方法。其间,我有幸与许多才华横溢的人共事并向他们学习,其中包括以下人员。

●SRI国际:鲍勃·博利斯(Bob Bolles)、亚当·切耶(Adam Cheyer)、伊丽莎白·丘吉尔(Elizabeth Churchill)、大卫·科琳(David Colleen)、布莱恩·戴维斯(Brian Davis)、迈克尔·埃里克森(Michael Eriksen)、杰伊·福基(Jay Feuquay)、马蒂·A.菲施勒(Marty A. Fischler)、亚伦·海勒(Aaron Heller)、李·艾弗森(Lee Iverson)、杰森·詹金斯(Jason Jenkins)、吕克·朱莉娅(Luc Julia)、伊万·G. 勒克莱尔(Yvan G. Leclerc)、帕特·林肯(Pat Lincoln)、克里斯·马林(Chris Marrin)、雷·C. 佩罗(Ray C. Perrault)和布莱恩·蒂尔尼(Brian Tierney)。

●皮克斯动画工作室:布拉德·安达尔曼(Brad Andalman)、大卫·巴拉夫(David Baraff)、伊恩·布诺(Ian Buono)、戈登·卡梅伦(Gordon Cameron)、埃德·卡特姆(Ed Catmull)、克里斯·科尔比(Chris Colby)、贝纳·柯林(Bena Currin)、加雷斯·戴维斯(Gareth Davis)、托尼·德罗斯(Tony DeRose)、迈克·费里斯(Mike Ferris)、库尔特·弗莱舍(Kurt Fleischer)、塞巴斯蒂安·格拉西亚(Sebastian Grassia)、埃里克·格雷戈里(Eric Gregory)、塔拉·埃尔南德斯(Tara Hernandez)、保罗·艾萨克斯(Paul Isaacs)、奥伦·雅各布(Oren Jacob)、迈克尔·卡斯(Michael Kass)、克里斯·金(Chris King)、布雷特·莱文(Brett Levin)、蒂姆·米利伦(Tim Milliron)、亚历克斯·莫尔(Alex Mohr)、科里·奥曼德(Cory Omand)、埃本·奥斯布蒂(Eben Osbty)、艾伦·普尔(Allan Poore)、克里斯·肖内曼(Chris Shoeneman)、帕特里克·朔克(Patrick Schork)、保罗·施特劳斯(Paul Strauss)、基里尔·维迪姆斯(Kiril Vidimče)、亚当·伍德伯里(Adam Woodbury)、余大卫(David Yu)、德克·范·盖尔德(Dirk van Gelder)和布拉德·韦斯特(Brad West)。

●面包屋动画工作室:萨姆·阿萨迪安(Sam Assadian)、塞巴斯蒂安·吉周(Sebastien Guichou)、阿诺德·拉莫莱特(Arnauld Lamorlette)、蒂里·劳赫利尔(Thierry Lauthelier)、伯努瓦·莱帕赫(Benoit Lepage)、杰夫·勒夫纳(Geoff Levner)、尼克·朗(Nick Long)、埃尔万·梅格雷特(Erwan Maigret)和巴里什·梅廷(Bariş Metin)。

●林登实验室:纳特·古德斯佩(Nat Goodspeed)、安德鲁·德莱克斯(Andrew de Laix)、霍华德·卢克(Howard Look)、布拉德·基滕布林克(Brad Kittenbrink)、布莱恩·麦格罗蒂(Brian McGroarty)、亚当·莫斯(Adam Moss)、马克·帕兰奇(Mark Palange)、吉姆·珀布里克(Jim Purbrick)和肯特·奎克(Kent Quirk)。

●PullString:雷内·亚当斯(Renée Adams)、奥莱娜·安德森(Olena Anderson)、杰夫·艾德洛特(Jeff Aydelotte)、肖恩·布莱克斯利(Shawn Blakesley)、迈克尔·钱(Michael Chann)、杰里米·西特林(Jeremy Cytryn)、菲拉特·恩德罗格鲁(Firat Enderoglu)、迈克尔·菲茨帕特里克(Michael Fitzpatrick)、约翰·富奇(John Fuetsch)、保罗·格拉克(Paul Gluck)、劳雷尔·古德哈特(Laurel Goodhart)、卢卡斯·艾夫斯(Lucas Ives)、帕特里克·库(Patrick Ku)、马切伊·库斯(Maciej Kus)、布莱恩·朗纳(Brian Langner)、罗宾·麦克唐纳(Robin McDonald)、威尔·米勒(Will Miller)、本杰明·莫尔斯(Benjamin Morse)、丹尼尔·辛托(Daniel Sinto)、奥雷里奥·蒂诺(Aurelio Tinio)和阿里·齐亚伊(Ali Ziaei)。

●苹果公司:乔·德西姆普利西斯(Joe DeSimpliciis)、格雷格·詹姆斯(Greg James)、托马斯·卡拉扎斯(Thomas Karatzas)、阿尔多·隆基(Aldo Longhi)、史蒂文·马丁(Steven Martin)、蒂姆·梅根(Tim Meighen)、丹·尼梅耶(Dan Niemeyer)、安托万·劳克斯(Antoine Raux)和斯坦利·塔尔哈默(Stanley Thalhammer)。

特别鸣谢伊万·G. 勒克莱尔博士(Dr. Yvan G. Leclerc),在我初入SRI国际时,他给我的生活带来重要的、积极的改变。伊万是我的第一位经理,也是我的挚友。他教会了我如何成为一名优秀的管理者,如何成为一名严谨的科学家和工程师,也教会了我如何充分享受生活。像伊万这样杰出的人物过早地离开我们,实在是一大遗憾。

我还要特别感谢爱思唯尔/摩根·考夫曼出版社(Elsevier/Morgan Kaufmann Publishers)的工作人员为本书的审阅、编辑、排版和出版所做的所有工作。没有他们的支持和努力,这些工作几乎不可能完成。具体来说,我要感谢托德·格林(Todd Green)、罗宾·戴(Robyn Day)、安德烈·奎洛(André Cuello)和梅丽莎·瑞维尔(Melissa Revell)对本书第1版的贡献,以及克里斯·卡萨罗普洛斯(Chris Katsaropoulos)、帕拉克·古普塔(Palak Gupta)、普拉萨娜·卡利亚纳拉曼(Prasanna Kalyanaraman)和格雷戈里·哈里斯(Gregory Harris)对本书第2版的贡献。

最重要的是,我要感谢我的妻子——吉娜维芙·维达内斯(Genevieve Vidanes),感谢她在我花费大量时间专注于电脑屏幕时给予我的支持和包容。写书可能会对个人和家庭生活造成很大干扰,但她在整个过程中一直鼓励我,同时知道何时让我暂停工作并休息。谢谢你,吉娜维芙,感谢你始终如一的爱和支持。你若不在我身边,我无法完成这一切。