通过虚拟接口类导出c ++类的可移植性

时间:2017-03-07 09:54:39

标签: c++ shared-libraries language-lawyer

我想编写一个可用作插件的库。该库是用C ++编写的,也应该用在C ++代码中。我发现this article描述了如何通过用户可见的纯虚拟接口结构导出c ++类。简而言之,代码如下:

struct VirtualInterface
{
    virtual MyExportedFunction() = 0;
}

class MyInterfaceImplementer : public VirtualInterface
{
    ...
    virtual MyExportedFunction(){...}
    ...
}

extern "C" MyAPI VirtualInterface* Factory(); // The only exported function

该文章的作者在某些时候指出:

  

无法有效支持COM的假设C ++编译器是   在Windows市场上注定要被遗忘。这就是为什么,如今,   通过抽象接口从DLL中公开C ++类将起作用   可靠地与Windows平台上的每个体面的C ++编译器一起使用。

我是否认为这种导出C ++类的方式依赖于编译器实现并且不能保证按标准工作?如果是,除了通过创建一个导出接口的每个功能的C接口之外,是否有可移植的方式?

2 个答案:

答案 0 :(得分:2)

您可以移植导出C ++类/接口on GNU/Linux and BSD because compilers support Itanium ABI

  

从GCC 3.2开始,C ++的GCC二进制约定基于一个独立于供应商的书面C ++ ABI,它专门针对64位Itanium,但也包括适用于任何平台的通用规范。这个C ++ ABI也在某些平台上由其他编译器供应商实现,特别是GNU / Linux和BSD系统。我们已经努力提供一个稳定的ABI,它将与未来的GCC版本兼容,但我们可能会遇到一些难以解决的问题。这些问题可能包括不同供应商对C ++ ABI的不同解释,ABI中的错误,或者不同编译器中ABI实现中的错误。当G ++生成可能与C ++ ABI不兼容的代码时,GCC的-Wabi开关会发出警告。

但是,如果C ++标准库中的类在接口中公开,那么API的实现和使用者必须使用相同的C ++库实现:

  

与C ++编译器一起使用的C ++库包括标准C ++库,其中包含C ++标准中定义的功能以及语言运行时支持。运行时支持包含在C ++ ABI中,但标准C ++库没有正式的ABI。该库的两个实现是可互操作的,如果一个遵循另一个的事实上的ABI,并且它们都使用相同的编译器构建,或者使用符合相同ABI的编译器来进行C ++编译和运行时支持。

     

当G ++和另一个C ++编译器符合相同的C ++ ABI,但他们通常使用的标准C ++库的实现不遵循标准C ++库的相同ABI时,使用这些编译器构建的目标文件可用于只有当他们使用相同的C ++库时,才能使用相同的程序。这需要在调用未使用常用库的编译器时指定C ++库头文件的位置。

由于上述支持COM的要求,这也适用于Windows编译器。虽然有一个destructors的皱纹:COM不使用析构函数,所以支持COM的两个编译器可能在将析构函数指针放在v表中的位置上有所不同。

答案 1 :(得分:0)

在 Doom 3 游戏中,引擎可执行文件 Doom3.exegamex86.dll 动态加载游戏玩法。游戏引擎接口完全按照您的描述通过虚拟函数公开(参见 review)。这在 Windows 和 Linux 上运行良好,允许创建 mod(例如 TheDarkMod 曾经那样生活)。

与动态链接相关的常见问题当然适用:

  1. CRT 库:静态链接它意味着您必须小心跨 DLL 边界传递的内容。动态链接它意味着每个人都必须使用相同的主要版本的编译器,至少在 Visual Studio 的情况下是这样。
  2. 在界面中使用 STL 是一个非常糟糕的主意,因为那样每个人都将不得不在 Windows 上使用相同的 Visual Studio 主要版本和相同类型的 CRT(调试/发布)。