类vtable如何跨共享库工作



假设我有一个名为libplugin的共享库。在这个共享库中,有一个类:

class Plugin
{
public:
virtual void doStuff();
};

我们还假设存在另一个名为libspecialplugin的共享库。它包含以下类和函数:

class SpecialPlugin : public Plugin
{
public:
virtual void doStuff();
};
Plugin *createSpecialPlugin()
{
return new SpecialPlugin;
}

现在,假设我更改Plugin并添加以下方法:

virtual void doMoreStuff();

我不编译libspecialplugin

当我这样做时会发生什么:

Plugin *plugin = createSpecialPlugin();
plugin->doMoreStuff();

我猜会发生以下情况之一:

  1. 应用程序崩溃
  2. 调用Plugin::doMoreStuff()方法

libspecialplugin库是否包含libplugin可以用来确定哪些方法被重写的信息,即使在运行时也是如此?我对这里到底应该发生什么有点模糊。

在使用这两个库的任何程序中,在两个不同的翻译单元中对同一类(Plugin)进行不同的定义,实际上违反了"一个定义规则"。

该标准规定(C++11 ISO 14882:2011,§3.2第5段):

类类型可以有多个定义(第9条)。。。在程序中,前提是每个定义都出现在不同的翻译单位,并提供满足以下要求的定义要求。给定这样一个名为D的实体在多个翻译单位,然后:

  • D的每个定义应由相同的令牌序列组成;以及

。。。

您的类Plugin有两个不同的定义,一个在libplugin中烘焙,另一个在librspecialplugin中,因此它不符合标准。

这个标准没有定义结果,所以任何事情都可能发生。

我必须添加一个巨大的免责声明,即"与vtables有关的一切都是由实现定义的。">

如果插件构造函数和析构函数没有在头中内联声明,这将很好地工作。它必须是对libplugin.so库中Plugin构造函数的实际函数调用。这意味着头必须声明构造函数和析构函数,但不能定义它们,以避免生成编译器的自动版本。

它看起来像:

class Plugin
{
public:
Plugin();
~Plugin();
virtual void doStuff();
};

还假设在类的末尾添加了新的虚拟函数。如果它导致vtable中的任何其他函数移动,则会破坏ABI。

然后,当构建插件基类时,它将使用额外的函数创建新的vtable。然后SpecialPlugin将调整其一个虚拟功能并完成构建。

其中一些可能取决于vtbl指针的特定编译器实现,但我已经看到了这种情况。

最新更新