为什么新的虚拟函数不会破坏二进制兼容性的现象?

why new virtual function will not break binary compatibility per phenomenon?

本文关键字:兼容性 二进制 虚拟 函数 为什么      更新时间:2023-10-16

我正在学习基于这个 KDE wiki 的二进制兼容性,并看到

将虚函数

添加到没有任何虚函数或虚基的类

会破坏兼容性。然后我试了一下。

假设我想创建一个FastString.dll来提供输出,这里是定义。

//FastString.h
#ifdef _DLL_EXPORT
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT __declspec(dllimport)
#endif
class LIB_EXPORT FastString
{
public:
FastString(void);
~FastString(void);
int length();
private:
int m_len;
unsigned char *m_bytes;
};

和实施

//FastString.cpp
#include "FastString.h"
FastString::FastString(void)
{
m_len = 0;
}
FastString::~FastString(void)
{
}
int FastString::length()
{
printf("Function of length, string len is %dn", m_len);
return m_len;
}

在第三个 exe 文件测试.exe中,使用了如下所示的快速字符串

// main.cpp
#include <conio.h>
#include "FastString.h"
int _tmain(int argc, _TCHAR* argv[])
{
FastString str;
str.length();
printf("Please input any key to exit...");
_getch();
return 0;
}

请注意:main.cpp包含的FastString.h是另一个文件,当我在 FastString 中添加虚拟函数时,修改是在 FastString.dll 下。

它们位于同一解决方案(编译器:VS2012)中,并成功生成。之后,我在 FastString.h 中添加一个新的虚拟函数。

virtual bool isEmpty();

在 FastString.cpp 中,我用简单的返回来实现它

bool FastString::isEmpty()
{
return false;
}

然后我单独构建 FastString.dll并重新运行 test.exe。输出与前一个输出相同,没有任何错误。
那么,为什么这种行为没有破坏二进制兼容性呢?
根据我的理解,实例str应该有一个vtable指针,并且内存布局必须已更改。
我也有一个基于 VS 工具的调试,发现str仍然没有_vptr,这是否意味着vtable是在编译器周期内创建的,而不是在链接周期内创建的?

非虚拟函数FastString::length()的调用与布局无关,DLL 中定义的函数知道实际的对象布局并找到正确的成员。您应该受到布局不兼容的影响,方法是公开m_len并从 DLL 外部访问它。

虽然没有关于VMT位置的一般规则,但它通常由编译器创建并放入某个特定的翻译单元(*.obj)中,即定义第一个虚函数的地方。有时,当所有虚函数都是内联的时,必须应用更高级的策略,并且它们通常涉及链接器。但通常,当使用较旧的标头编译器时,将没有足够的提示涉及 VMT 的存在,并且不会为该对象创建 VMT 指针。