关于c#:通过指向基类的指针实现虚拟方法调用的CLR

CLR implementation of virtual method calls via pointer to base class

直到我知道如何通过C/clr调用所需的虚拟方法时,我才能睡觉。在我的书中,Richter写了不少于clr确定对象的实际类型并调用适当的方法的内容。例如,在C++中,多态类的每个实例都存储指向虚拟表的指针。但在C中,不是指向虚拟表的指针,实例数据存储了一些syncblk索引和typehandle。不理解typehandle与C中的指针的区别。类型句柄的作用是什么?例如,在C++中,我们有

1
2
3
4
5
6
7
8
9
10
11
class A
{
   int a;
   public virtual void show() {}
};

class B: public A
{
   int b;
   public virtual void show() {}
};

A和B类的实例在内存中的外观,我用peseudocode编写

1
2
3
4
5
6
7
8
9
10
11
12
13
A:
{
  vtptr;   // pointer to  A vt
  a;
}


B:
{
  vtptr;  // pointer to  A vt + B vt
  a;
  b;
}

那么,在C++中,我们运行代码

1
2
A* pa = new B();
pa->show();

很明显,我们创建了B实例并将其强制转换为一个类型,但是我们不会丢失show()的重写地址,感谢您调用B::show()。对于C/clr如何执行基类型的强制转换并定义虚方法调用的类似示例,我真的需要理解。请帮助!我很高兴知道所有的技术细节


"Typehandle"是一个流行的错误。它实际上是方法表指针,它在CLR源中命名。一个管理对象的方法与一个C+V-Table功能非常相似,一个指针表与该类方法相似。一个小的差别是,它不只是包含虚拟方法,它还被用来编纂一种方法。

所以,它的工作方式完全一样,一个简单的间接呼唤对着桌子的入口。Jitter知道表中的方法指针的胶印件,就像C+Compiler does。这个运行就像本地的C++Code一样快。

你的Snippet written in C 35;and used like this:

1
2
    A obj = new B();
    obj.show();

Produces this 32 bit machine code at runtime:

ZZU1

当你可以从胶印(0x38)中说出的时候,方法表中的指针比方法多。您可以在SSCL20源代码中找到详细信息。

The snippet in native C+++and used like this:

1
2
3
4
5
6
int main()
{
    A* obj = new B;
    obj->show();
    return 0;
}

生产这32位机器代码:

1
2
3
4
5
6
7
8
9
10
11
01361010  push        0Ch                     ; size of B object
01361012  call        operator new (136104Ch) ; call operator new
01361017  add         esp,4                   ; __cdecl stack cleanup
0136101A  test        eax,eax                 ; handle null pointer
0136101C  je          main+1Fh (136102Fh)
0136101E  mov         dword ptr [eax],offset B::`vftable' (1362100h)  ; initialize v-table

01361024  mov         edx,dword ptr [eax]     ; obtain v-table pointer from object
01361026  mov         ecx,eax                 ; setup this pointer
01361028  mov         eax,dword ptr [edx]     ; get method pointer
0136102A  call        eax                     ; indirect call to show()

制造商的呼叫是由于语言规则引起的更高的比特。方法呼叫是一样的,只是不同的代码-GEN。在早期一代五丁基处理器上,效率较高。