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

Portability of exporting a c++ class via virtual interface class

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

struct VirtualInterface
{
    virtual MyExportedFunction() = 0;
}

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

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

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

A hypothetical C++ compiler that fails to support COM efficiently is doomed to oblivion in the Windows market. That is why ,nowadays, exposing a C++ class from a DLL via an abstract interface will work reliably with every decent C++ compiler on the Windows platform.

这种导出 C++ 的方式 class 依赖于编译器实现,并且不能保证按标准工作,我是否理解正确?如果是,是否有一种可移植的方法,除了通过创建一个导出接口的每个函数的 C 接口?

您可以导出 C++ class/interface on GNU/Linux and BSD because compilers support Itanium ABI:

Starting with GCC 3.2, GCC binary conventions for C++ are based on a written, vendor-neutral C++ ABI that was designed to be specific to 64-bit Itanium but also includes generic specifications that apply to any platform. This C++ ABI is also implemented by other compiler vendors on some platforms, notably GNU/Linux and BSD systems. We have tried hard to provide a stable ABI that will be compatible with future GCC releases, but it is possible that we will encounter problems that make this difficult. Such problems could include different interpretations of the C++ ABI by different vendors, bugs in the ABI, or bugs in the implementation of the ABI in different compilers. GCC’s -Wabi switch warns when G++ generates code that is probably not compatible with the C++ ABI.

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

The C++ library used with a C++ compiler includes the Standard C++ Library, with functionality defined in the C++ Standard, plus language runtime support. The runtime support is included in a C++ ABI, but there is no formal ABI for the Standard C++ Library. Two implementations of that library are interoperable if one follows the de-facto ABI of the other and if they are both built with the same compiler, or with compilers that conform to the same ABI for C++ compiler and runtime support.

When G++ and another C++ compiler conform to the same C++ ABI, but the implementations of the Standard C++ Library that they normally use do not follow the same ABI for the Standard C++ Library, object files built with those compilers can be used in the same program only if they use the same C++ library. This requires specifying the location of the C++ library header files when invoking the compiler whose usual library is not being used.

由于上述支持 COM 的要求,这也可能适用于 Windows 编译器。但是析构函数有一个问题:COM 不使用析构函数,因此支持 COM 的两个编译器可能在将析构函数指针放在 v-table.

中的位置上有所不同。

在 Doom 3 游戏中,引擎可执行文件 Doom3.exegamex86.dll 动态加载游戏玩法。游戏引擎接口完全按照您的描述通过虚拟函数公开(参见 review). This works perfectly well on Windows and Linux, allowing to create mods (e.g. TheDarkMod 曾经这样生活)。

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

  1. CRT 库:静态链接它意味着您必须小心跨过 DLL 边界的内容。动态链接它意味着每个人都必须使用相同的主要版本的编译器,至少在 Visual Studio.
  2. 的情况下是这样
  3. 在界面中使用 STL 是一个非常糟糕的主意,因为这样每个人都必须在 [=30= 上使用相同的 Visual Studio 主版本和相同类型的 CRT (debug/release) ].