《C++ API 设计》是一本非常不错的书,该书内容远远超过了它标题所指的 C++ API 设计,它不仅仅讲述了与编程语言无关的 API 设计需要遵循的一些规范,同时也介绍了很多 C++开发中需要遵守一些准则,如果在开发中能遵循这些准则,将有利于我们写出高质量的代码。

读罢该书,受益匪浅,本文将该书中我认为比较受用的部分摘录下来。

  • 只有两种编程语言:一种是天天挨骂的,另一种是没人用的。

  • 良好的 API 设计的首要目标是:在为客户提供所需功能的前提下,使用新发布的 API 对客户的代码造成的影响应该最小,理想的情况下应该是零影响。

  • C++ 没有包私有的概念,而是使用更加宽泛的友元的概念,以允许指定的类和方法访问某个类的受保护的和私有的成员。虽然友元可以用来加强封装,但是如果使用不当,它会向用户暴露过多的内部细节。

  • 类的数据成员应该始终声明为私有的,而不是公有的或受保护的。

  • 类只应该定义做什么,而不是怎么做。不要将某一个功能的具体实现步骤暴露出来,即便定义为私有的,也尽量不要这样做。可以使用Pimpl技巧来将所有的私有数据成员和函数隔离到一个.cpp 文件中独立实现的类或结构体内。

  • 不要过度承诺。当不确定是否需要某个接口时,就不要提供此接口。谨记奥卡姆(Occam)剃刀原理:若无必要,勿增实体。

  • 谨慎添加虚函数,使用虚函数要意识到其潜在的隐患:

    1. 对基类看似无害的修改可能会给客户带来不利的影响。
    2. 客户可能会以你根本无法预料的方式来使用 API。
    3. 客户可能采用不正确的或易于出错的方式来扩展 API。
    4. 重写虚函数可能破坏类的内部原有逻辑的完整性。
  • 使用虚函数要注意的方面:

    1. 虚函数的调用必须在运行时查虚函数表才能决定,无法在编译时决定。
    2. 使用虚函数需要维护虚函数表指针,进而增加对象的大小。
    3. 添加、重排或者移除虚函数会破坏二进制兼容性。因为虚函数调用通常用类的虚函数表的整型偏移量来表示,所以改变虚函数的顺序,或者执行可能会引起其他虚函数的顺序发送变化的操作,都需要重新编译现有代码。
    4. 如果类包含了任一虚函数,那么必须将析构函数声明为虚函数。这样子类就可以释放其可能申请的额外资源。
    5. 绝不在构造函数或析构函数中调用虚函数,这些调用不会指向之类。
  • Sutter 建议接口应该是非虚的,同时在适当的情况下使用模板方法设计模式。

  • 给出清晰的、描述性强的且恰当的名字是 API 设计中最困难的任务之一。

  • 避免编写拥有多个相同类型参数的函数。

  • 使用一致的(统一规范)函数命令和参数顺序。

  • API 接口应该是平台独立的。不要将平台相关的#if#ifdef语句放在公共的 API 中,因为这些语句暴露了实现的细节,并使 API 因平台而异。

  • 优秀的 API 表现为松耦合和高内聚。

  • 除非确实需要#include类的完整定义,否则应该为类使用前置声明。

  • 通常,优秀的软件工程实践的目标是去除冗余,即确保每个重要的知识点或行为有且仅有一次实现。而代码复用意味着耦合,因此略微的增加重复以断绝过分的耦合关系有时是值得的。

《C++ API 设计》[美] Martin Reddy 著;刘晓娜,臧秀涛,林健 译