class vtable 如何跨共享库工作?
How does a class vtable work across shared libraries?
假设我有一个名为 libplugin
的共享库。在这个共享库中,有一个class:
class Plugin
{
public:
virtual void doStuff();
};
我们还假设还有另一个名为 libspecialplugin
的共享库。它包含以下 class 和功能:
class SpecialPlugin : public Plugin
{
public:
virtual void doStuff();
};
Plugin *createSpecialPlugin()
{
return new SpecialPlugin;
}
现在,假设我更改 Plugin
并添加以下方法:
virtual void doMoreStuff();
我不重新编译libspecialplugin
。
当我这样做时会发生什么:
Plugin *plugin = createSpecialPlugin();
plugin->doMoreStuff();
我猜会发生以下情况之一:
- 应用程序崩溃
- 调用了
Plugin::doMoreStuff()
方法
libspecialplugin
库是否包含 libplugin
可用于确定其哪些方法被覆盖的信息 - 即使在运行时?我有点不清楚这里究竟应该发生什么。
我必须添加巨大的免责声明 "Everything to do with vtables is implementation defined."
如果 插件构造函数和析构函数未在 header 中声明为内联,这将正常工作 。它必须是对 libplugin.so 库中插件构造函数的实际函数调用。这意味着 header 必须声明构造函数和析构函数但不定义它们以避免生成编译器的自动版本。
看起来像:
class Plugin
{
public:
Plugin();
~Plugin();
virtual void doStuff();
};
还提供了在class末尾添加新的虚函数。如果它导致 vtable 中的任何其他函数移动,那将破坏 ABI。
然后当构建插件基础 class 时,它将创建具有额外功能的新 vtable。然后SpecialPlugin会调整自己的一个虚函数,完成构建。
其中一些可能取决于 vtbl 指针的特定编译器实现,但我已经看到它完成了。
您在使用这两个库的任何程序中的两个不同翻译单元中对相同的 class (Plugin
) 进行了不同的定义,这实际上违反了 "One Definition Rule"。
标准说(C++11 ISO 14882:2011,§3.2 第 5 段):
There can be more than one definition of a class type (Clause 9) ...
in a program provided that each definition appears in a different
translation unit, and provided the definitions satisfy the following
requirements. Given such an entity named D defined in more than one
translation unit, then:
- each definition of D shall consist of the same sequence of tokens; and
...
你的classPlugin
有两种不同的定义,一种是baked into libplugin,另一种是libspecialplugin,所以不符合标准。
这个结果没有被标准定义,所以任何事情都有可能发生。
假设我有一个名为 libplugin
的共享库。在这个共享库中,有一个class:
class Plugin
{
public:
virtual void doStuff();
};
我们还假设还有另一个名为 libspecialplugin
的共享库。它包含以下 class 和功能:
class SpecialPlugin : public Plugin
{
public:
virtual void doStuff();
};
Plugin *createSpecialPlugin()
{
return new SpecialPlugin;
}
现在,假设我更改 Plugin
并添加以下方法:
virtual void doMoreStuff();
我不重新编译libspecialplugin
。
当我这样做时会发生什么:
Plugin *plugin = createSpecialPlugin();
plugin->doMoreStuff();
我猜会发生以下情况之一:
- 应用程序崩溃
- 调用了
Plugin::doMoreStuff()
方法
libspecialplugin
库是否包含 libplugin
可用于确定其哪些方法被覆盖的信息 - 即使在运行时?我有点不清楚这里究竟应该发生什么。
我必须添加巨大的免责声明 "Everything to do with vtables is implementation defined."
如果 插件构造函数和析构函数未在 header 中声明为内联,这将正常工作 。它必须是对 libplugin.so 库中插件构造函数的实际函数调用。这意味着 header 必须声明构造函数和析构函数但不定义它们以避免生成编译器的自动版本。
看起来像:
class Plugin
{
public:
Plugin();
~Plugin();
virtual void doStuff();
};
还提供了在class末尾添加新的虚函数。如果它导致 vtable 中的任何其他函数移动,那将破坏 ABI。
然后当构建插件基础 class 时,它将创建具有额外功能的新 vtable。然后SpecialPlugin会调整自己的一个虚函数,完成构建。
其中一些可能取决于 vtbl 指针的特定编译器实现,但我已经看到它完成了。
您在使用这两个库的任何程序中的两个不同翻译单元中对相同的 class (Plugin
) 进行了不同的定义,这实际上违反了 "One Definition Rule"。
标准说(C++11 ISO 14882:2011,§3.2 第 5 段):
There can be more than one definition of a class type (Clause 9) ... in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then:
- each definition of D shall consist of the same sequence of tokens; and
...
你的classPlugin
有两种不同的定义,一种是baked into libplugin,另一种是libspecialplugin,所以不符合标准。
这个结果没有被标准定义,所以任何事情都有可能发生。