C++公共API的最佳实践是什么?
我正在开发一个C++项目,其中有多个命名空间,每个命名空间中都有多个对象。一些对象具有相同的名称,但位于不同的命名空间中。目前,每个对象都有自己的.cpp文件和.h文件。我不确定如何表达这个问题......创建第二个.h文件来仅公开公共API是否合适?对于每个命名空间或每个对象,应该有一个.h文件还是其他范围?对于创建C++库的公共API,可能的最佳实践是什么?
感谢任何帮助, Chenz
有时候,在每个.cpp和.h文件对中都拥有一个单一的类,并将命名空间层次结构作为目录结构,这样做很方便。
例如,如果你有这个类:
namespace stuff {
namespace important {
class SecretPassword
{
...
};
}
}
接下来它将分为两个文件:
/stuff/important/SecretPassword.cpp
/stuff/important/SecretPassword.h
另一种可能的布局可能是:
/src/stuff/important/SecretPassword.cpp
/include/stuff/important/SecretPassword.h
你好,
我的建议是看一下C++的Handle-Body惯用语,有时也被称为Cheshire Cat。这里是James Coplien的原始论文,其中包含了这种惯用语。
这是一种著名的方法,可将公共API与实现分离。
希望能对你有所帮助。
我认为最好由您自己决定,这取决于这是什么类型的“库”。
您的API提供一个“操作”吗?还是只处理一个抽象的“数据类型”?例如zlib和libpng。两者都只有一个头文件,可以提供执行库所用的所有内容。
如果您的库是一组不相关(甚至相关)的类,它们是否达到了相同的目标,请为每个子集提供自己的头文件。主要示例是boost。
这是我通常做的:
“有些对象具有相同的名称,但位于不同的命名空间中”
这就是为什么存在命名空间的原因。
“创建第二个.h文件来仅公开公共API是否合适?”
您应该始终仅公开公共API。但是公开公共API是什么意思?如果只是头文件,那么由于公共API依赖于私有API,私有API将被公共API包含。要公开公共API,请使用宏标记公共函数/类(在Windows情况下,将公共函数导出到符号表;可能很快会被Unix系统采用)。因此,您应该定义一个类似于MYLIB_API或MYLIB_DECLSPEC的宏,只需检查一些现有库和MS declspec文档即可。通常,非公共API将保留在子目录中,因此不会参加库的用户。
“每个命名空间或每个对象或其他范围应该有一个.h文件吗?”
我更喜欢Java风格,每个头文件只有一个public类。我发现以这种方式编写的库比混合文件和结构名称的库更清晰易读。但是在某些情况下,我会打破这个规则,特别是涉及模板时。在这种情况下,我会给出#warning消息,不要直接包含头文件,并在注释中仔细解释正在发生的事情。
非常好的回答LiraNuna。
您是为应用程序或库提供API吗?
应用程序API通常只提供查询应用程序状态或尝试更改该状态的方法。在这种情况下,您通常会在单独的头文件中有不同的接口声明。然后,您的对象将实现此接口以处理API请求。
库通常公开可重复使用的对象。在这种情况下,一般来说,您的API只是头文件中的公共方法。
我同意文档中所说的 - 一个文件只有一个类。99.9%的情况下都是如此!
另外,请考虑使用哪些文件名。即使它们包含的类可能在不同的命名空间中,但在不同目录中具有相同名称的多个头文件通常是一个坏主意。
特别是如果这是一个公共API,您可能不能控制库使用者定义的include路径,因此构建可能会找到错误的路径。调整include路径的顺序绝对不是我推荐的解决方案!
我们使用Namespace-Class.h
的命名约定来明确标识文件中的类。
#include "Mylib-Graphics-Formats-JpegLoader.h"
和 #include "mylib/graphics/formats/JpegLoader.h"
之间有什么区别?你仍然必须以某种方式输入完整的“路径”吗? - Steve Follymylib
所在的位置,那么就不会产生歧义了。但是你不能总是保证用户会做正确的事情(或者你可以保证他们会做错误的事情!)。 - Steve Folly