为什么在头文件中定义的C++虚函数可能无法在vtable中编译和链接?

0xD*_*EEF 6 c++ virtual interface

情况如下.我有共享库,其中包含类定义 -

QueueClass : IClassInterface
{
   virtual void LOL() { do some magic}
}
Run Code Online (Sandbox Code Playgroud)

我的共享库初始化类成员

QueueClass *globalMember = new QueueClass();
Run Code Online (Sandbox Code Playgroud)

我的共享库导出C函数返回指向globalMember的指针 -

void * getGlobalMember(void) { return globalMember;}
Run Code Online (Sandbox Code Playgroud)

我的应用程序像这样使用globalMember

((IClassInterface*)getGlobalMember())->LOL();
Run Code Online (Sandbox Code Playgroud)

现在非常简单的东西 - 如果我不从共享库引用LOL,那么LOL没有链接并从应用程序调用它引发异常.原因 - VTABLE包含nul代替指向LOL()函数的指针.

当我将.L文件中的LOL()定义移动到.cpp时,突然它出现在VTABLE中,一切都很好.是什么解释了这种行为?!(gcc编译器+ ARM架构_)

def*_*ode 6

链接器是这里的罪魁祸首.当函数是内联函数时,它有多个定义,每个cpp文件中有一个定义它被引用.如果您的代码从不引用该函数,则永远不会生成它.

但是,vtable布局是在编译时使用类定义确定的.编译器可以轻松地告诉它LOL()是一个虚函数,并且需要在其中有一个条目vtable.

当它获得应用程序的链接时间时,它会尝试填写所有值,QueueClass::_VTABLE但找不到定义LOL()并将其留空(null).

解决方案是LOL()在共享库中的文件中引用.简单的事情&QueueClass::LOL;.您可能需要将其分配给throw away变量以使编译器停止抱怨语句而不起作用.

  • @ 0xDEAD BEEF,如果没有通过指针或引用调用虚函数,编译器可以内联虚函数.即`QueueClass q; q.LOL();`编译器知道它将调用QueueClass :: LOL并且通过vtable将是多余的. (2认同)