2017-01-11 84 views
2

假设我有一个名为libplugin的共享库。在此共享库中,有一类:类vtable如何在共享库上工作?

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库是否包含信息tha t libplugin可用于确定哪些方法被覆盖 - 即使在运行时?我对这里应该发生的事情有点模糊。

+0

没有“共享库”这样的东西,这是一个矛盾。你所谈论的是共享对象代码,它像普通对象代码一样工作,只是总是独立定位(现在,常规对象代码通常是独立于位置的,但并不总是需要)。 – curiousguy

回答

6

通过在使用这两个库的任何程序中的两个不同翻译单元中具有相同的类(Plugin),您实际上违反了“一个定义规则”。

的标准说(C++ 11 ISO 14882:2011,§3.2第5段):

可以有一个类类型(第9)的多于一个的定义... 提供的程序中,每个定义出现在不同的翻译单元 中,并且提供的定义满足以下 要求。在多于一个 翻译单元,然后定义给定这种命名d实体:

  • d的每个定义应包括令牌的相同序列的;和

...

Plugin类有两个不同的定义,一个烤成libplugin和其他在libspecialplugin,所以它不符合该标准。

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

+0

Oblicatory [nasal daemons](http://i.imgur.com/Zomm1zq.jpg)。 – wilx

0

我必须添加一个巨大的免责声明,即“与vtables相关的一切都是实现定义的。”

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

它看起来像:

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

还提供了新的虚拟功能在类的末尾。如果它导致vtable中的任何其他功能移动,那么将会破坏ABI。

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

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