c ++插件:传递多态对象可以吗?

时间:2015-02-12 23:20:35

标签: c++ plugins binary system

使用动态库时,我知道我们应该只跨越边界传递普通旧数据结构。那么我们可以将指针传递给base吗?

我的想法是应用程序和库都可以知道一个公共接口(纯虚方法,= 0)。 库可以实例化该接口的子类型, 应用程序可以使用它。

例如,以下代码段安全吗?

// file interface.h

class IPrinter{
    virtual void print(std::string str) = 0;
 };

-

// file main.cpp

int main(){
    //load plugin...
    IPrinter* printer = plugin_get_printer();
    printer->print( std::string{"hello"} );
}

-

// file plugin.cpp (compiled by another compiler)

IPrinter* plugin_get_printer(){
    return new PrinterImpl{};
}

2 个答案:

答案 0 :(得分:1)

类中存在虚函数意味着您的类将具有vtable,不同的编译器以不同方式实现vtables。

因此,如果你在DLL调用中使用带有虚方法的类,而另一方使用的编译器与你正在使用的编译器不同,那么结果可能是引人注目的崩溃。

在您的情况下,DLL创建的PrinterImpl将以某种方式构建vtable,但printer->print()中的main()调用将尝试解释{的vtable {1}}以不同的方式解析IPrinter方法调用。

答案 1 :(得分:1)

此代码段不安全:

  • DLL边界的两边不使用相同的编译器。这意味着name mangling(对于函数名称)和vtable布局(对于虚函数)可能不相同(特定于实现。

  • 双方的堆也可能以不同方式进行管理,因此如果在DLL中没有完成,则会有与删除对象相关的风险。

这个article很好地展示了二进制兼容接口的主要挑战。

然而,你可以将指针作为POD的一部分传递到镜像的另一侧,只要另一部分不通过iself使用它(f.ex:你的app将一个指向配置对象的指针传递给DLL。稍后另一个DLL函数返回指向你的应用程序的指针。然后你的应用程序可以按预期使用它(至少如果它不是指向不再存在的本地对象的指针)。