我知道这是一个旧线程,但没有人提到 ABI 接口或特定的编译器问题。所以我想我会的。
这基本上是基于这样的概念:您要么编写带有标头的库以分发给人们,要么重用自己而不是将所有内容都放在标头中。如果您正在考虑重用头文件和源文件并在每个项目中重新编译它们,那么这实际上并不适用。
基本上,如果您编译您的 C++ 代码并使用一个编译器构建一个库,然后用户尝试将该库与不同的编译器或同一编译器的不同版本一起使用,那么您可能会因为二进制文件而出现链接器错误或奇怪的运行时行为不兼容。
例如,编译器供应商经常在版本之间更改其 STL 的实现。如果您在接受 std::vector 的库中有一个函数,那么它期望该类中的字节按照编译库时的排列方式排列。如果在新的编译器版本中,供应商对 std::vector 进行了效率改进,那么用户的代码会看到可能具有不同结构的新类并将该新结构传递到您的库中。一切都从那里走下坡路……这就是为什么建议不要跨库边界传递 STL 对象的原因。这同样适用于 C 运行时 (CRT) 类型。
在谈到 CRT 时,您的库和用户的源代码通常需要链接到同一个 CRT。使用 Visual Studio,如果您使用多线程 CRT 构建库,但用户链接到多线程调试 CRT,那么您将遇到链接问题,因为您的库可能找不到它需要的符号。我不记得它是哪个函数,但是对于 Visual Studio 2015,Microsoft 内联了一个 CRT 函数。突然,它出现在标头而不是 CRT 库中,因此希望在链接时找到它的库不再能够做到这一点,这会产生链接错误。结果是这些库需要使用 Visual Studio 2015 重新编译。
如果您使用 Windows API,但您使用与库用户不同的 Unicode 设置进行构建,也可能会出现链接错误或奇怪的行为。这是因为 Windows API 具有使用 Unicode 或 ASCII 字符串和宏/定义的函数,它们会根据项目的 Unicode 设置自动使用正确的类型。如果您通过库边界传递一个错误类型的字符串,那么事情会在运行时中断。或者你可能会发现程序一开始就没有链接。
这些事情也适用于从其他第三方库(例如特征向量或 GSL 矩阵)跨库边界传递对象/类型。如果第 3 方库在你编译你的库和你的用户编译他们的代码之间改变了他们的标题,那么事情就会中断。
基本上,为了安全起见,您可以跨库边界传递的唯一内容是内置类型和普通旧数据 (POD)。理想情况下,任何 POD 都应该在您自己的头文件中定义的结构中,并且不依赖任何第三方头文件。
如果您提供仅标头库,那么所有代码都会使用相同的编译器设置和相同的标头进行编译,因此很多这些问题都会消失(提供您和您的用户使用的第三方库的版本与 API 兼容)。
但是上面已经提到了一些负面因素,例如增加了编译时间。此外,您可能正在经营一家企业,因此您可能不想将所有源代码实现细节交给所有用户,以防其中有人窃取它。