我正在学习基于此KDE wiki的二进制兼容性,并看到
add a virtual function到没有任何虚拟功能或虚拟基地的课程
将破坏兼容性。然后我试了一下。
假设我想创建一个 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 %d\n", m_len);
return m_len;
}
在第三个exe文件 test.exe 中,使用如下的FastString
// 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 是在编译器下创建的期间,而不是链接期间?
答案 0 :(得分:0)
调用非虚函数FastString::length()
是独立于布局的,并且在DLL中定义的函数知道实际的对象布局并找到正确的成员。通过使m_len
公开并从DLL外部访问它,您应该遇到布局不兼容问题。
虽然没有关于VMT所在位置的一般规则,但它通常由编译器创建并放入某个特定的转换单元(* .obj)内,即定义第一个虚拟函数的位置。有时,例如,当所有虚函数都是内联时,必须应用更高级的策略,并且它们通常涉及链接器。但通常在使用较旧的头文件编译器时,没有足够的提示涉及VMT的存在,并且不会为该对象创建VMT指针。