void(**vt)()=*(void(***)())ptr;c++中虚拟表的辅助变量

void (**vt)() = *(void (***)())ptr; a helper variable for virtual table in c++

本文关键字:void 变量 虚拟 vt ptr c++      更新时间:2023-10-16

我在以下链接中发现了这种技术:http://www.codeproject.com/Tips/90875/Displaying-vtable-when-debugging

在那里,他使用了一个辅助变量

void (**vt)() = *(void (***)())ptr;

以帮助显示虚拟功能表。

但如果我把它改成

void (**vt)() = (void (**)())ptr;

它与前一个不一样。

有人能帮我解释一下这里有什么魔术吗?

为了清楚起见,我们引入一个typedef。

typedef void (**thing)();

然后第一个代码是

thing vt = *(thing*) ptr;

和第二个

thing vt = (thing) ptr;

也就是说,第一个说"把ptr当作一个指向一个东西的指针,给我它指向的东西",第二个说"当作一个东西对待ptr"
区别应该是显而易见的。

它运行的原因对于Visual C++编译器和Visual Studio调试器都非常具体。

如果调试器不知道对象的真正类型,它会显示它所知道的内容,即它是基类的实例,并且它只知道基类的vtable有多少条目。

(您在这里遗漏了一个关键部分,那就是将预期数量的表条目添加到监视窗口中的项目中。这使得调试器将内存显示为您所说的元素数组。)

因此,诀窍在于为vtable创建一个名称,并告诉调试器要从表中显示多少元素。

在许多C++实现中,虚拟表指针是对象的第一个sizeof(void (**)())字节。当您取消引用该指针时,您将获得实际虚拟表的起始地址。这就是工作代码的含义。

cdecl程序在这里可能有点帮助:

cdecl> explain void (***foo)()
declare foo as pointer to pointer to pointer to function returning void
cdecl> explain void (**foo)()
declare foo as pointer to pointer to function returning void

第一个代码将指向对象的指针强制转换为适当的可取消引用指针(指向函数的指针的指针,void (***)()),然后取消引用它以获取虚拟表的起始地址,该虚拟表的类型为void (**)()pointer to pointer to function),其指向类型为CCD_ 5(指向函数的指针的数组)的虚拟表的开头。

第二种方法只是将指向对象的指针强制转换为指向返回void的函数的指针;变量vt中存储的地址就是对象的地址。

class Object {
public:
    virtual void foo() {};
};
Object x;
// is approximately equivalent to 
struct Object {
    void (**_vtable)();
};
void _Object_foo(Object this) {
}
// this does not really compile, however,
// because a pointer mismatch
void (*_vtable_for_Object[])() = {
    _Object_foo
};
Object y;
y._vtable = _vtable_for_Object;

因此,通过具有

Object *ptr = new Object();
// x now points to a block of memory,
// whose first bytes are void (**_vtable)()
// then
void (**vt)() = *(void (***)())ptr;
// is equivalent in our analogy to
void (**vt)() = ptr->_vtable;
// except that the C++ does not allow you to
// access the virtual table directly without
// the trickery of the former