简体   繁体   English

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

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

I found this technique in the following link: http://www.codeproject.com/Tips/90875/Displaying-vtable-when-debugging 我在以下链接中找到了这种技术: http//www.codeproject.com/Tips/90875/Displaying-vtable-when-debugging

and there, he uses one helper variable 在那里,他使用一个辅助变量

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

to help display the virtual function table. 帮助显示虚拟功能表。

But if I change it to 但如果我把它改成

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

it does not work as the previous one. 它不像以前的那样工作。

Could someone help me to explain what magic plays here, please? 有人可以帮我解释一下这里有什么魔法吗?

Let's introduce a typedef for clarity. 我们为了清晰起见介绍一个typedef。

typedef void (**thing)();

Then the first code is 然后第一个代码是

thing vt = *(thing*) ptr;

and the second 第二个

thing vt = (thing) ptr;

That is, the first says "treat ptr as a pointer to a thing, and give me what it points at" and the second "treat ptr as a thing". 也就是说,第一个说“将ptr视为指向某个东西的指针,然后给我指出的东西”,第二个“将ptr视为一个东西”。
The difference should be obvious. 差异应该是显而易见的。

The reason it works at all is very specific to both the Visual C++ compiler and the Visual Studio debugger. 在所有工作的原因是非常具体的,以双方的Visual C ++编译器和Visual Studio调试器。

If the debugger doesn't know what type the object really is, it displays what it knows, which is that it's an instance of the base class, and it only knows how many entries the vtable of the base class has. 如果调试器不知道对象到底是什么类型,它会显示它所知道的内容,即它是基类的实例,它只知道基类的vtable有多少条目。

(You left out a crucial part here, which is to add the expected number of table entries to the item in the watch window. This makes the debugger display that memory as an array of as many elements as you say.) (你在这里省略了一个关键部分,即在观察窗口中向项目添加预期数量的表项。这使得调试器将该内存显示为一个包含所述元素的数组。)

So the trick consists of inventing a name for the vtable, and telling the debugger how many elements to display from the table. 因此,技巧包括为vtable创建一个名称,并告诉调试器从表中显示多少元素。

The virtual table pointer in many C++ implementations is the first sizeof(void (**)()) bytes of the object. 许多C ++实现中的虚拟表指针是对象的第一个sizeof(void (**)())字节。 When you dereference that pointer you will get the starting address of the real virtual table. 当您取消引用该指针时,您将获得真实虚拟表的起始地址。 That is the meaning of the working code. 这就是工作代码的含义。

The cdecl program might be of bit of a help here: 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

The first code casts the pointer to your object as a properly derefereancable pointer ( pointer to pointer to pointer to function , void (***)() ), and then dereferences it to acquire the starting address to the virtual table, which is of a type void (**)() ( pointer to pointer to function ), which points to the beginning of the virtual table that is of type void (*[])() ( array of pointer to function ). 第一个代码将指向对象的指针转换为正确的可解除引用的指针( 指向指向函数的指针的指针void (***)() ),然后取消引用它以获取虚拟表的起始地址,该表是类型void (**)()指向函数的指针 ),它指向虚拟表的开头,类型为void (*[])()指向函数的指针数组 )。

The second one just casts your pointer to object to a pointer to a pointer to a function returning void; 第二个只是将指向对象的指针强制转换为指向返回void的函数的指针; the address stored in the variable vt is just the address of your object. 存储在变量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;

Thus by having 因此有了

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM