簡體   English   中英

如何在c ++和c#中實現vtables?

[英]How are vtables implemented in c++ and c#?

讓我們有這種情況(在c ++中,在c#類A中,B是接口):

class A { virtual void func() = 0; };
class B { virtual void func() = 0; };
class X: public A, public B { virtual void func(){ var = 1; } int var;};

X * x = new X; // from what I know, x have 2 vtables, is this the same in c#?
A * a = (A*)x; // a == x
B * b = (B*)x; // here b != x, so when calling b->func(), how is the address of var correct?

c#編譯器是否始終創建一個vtable? 在投射時是否會進行任何指針修正?

如果我用g ++學習這個派生版本

class X: public A, public B { 
   unsigned magic;
 public:
   X() : magic(0xcafebabe) {};
   virtual void func(){ var = 1; } int var;
};

extern "C" int main() 
{
   X * x = new X; // from what I know, x have 2 vtables, is this the same in c#?
   A * a = (A*)x; // &a == &x
   B * b = (B*)x; // here &b != &x, so when calling b->func(), how is the address of var correct?
   printf("%p -- %p -- %p\n", x, a, b);

   unsigned* p = (unsigned*)((void*) x);
   unsigned *q = (unsigned*)(p[1]);
   printf("x=[%x %x %x %x]\n",p[0],p[1],p[2],p[3]);
   p = (unsigned*)(p[0]);
   printf("a=[%x %x %x %x]\n",p[0],p[1],p[2],p[3]);
   printf("b=[%x %x %x %x]\n",q[0],q[1],q[2],q[3]);

}

事實證明,在C ++中b == a + 1,所以X的結構是[vtable-X + A] [vtable-B] [magic] [var]檢查更深(nm ./a.out),vtable -X + a包含對X :: func的引用(正如人們所期望的那樣)。 當你將X轉換為B時,它調整了指針,以便VTBL for B函數出現在代碼所期望的位置。

你真的打算“隱藏”B :: func()嗎?

B的vtbl看起來像是對X的“trampoline”的引用,它在調用X + A vtbl所持有的“常規”X :: func之前將對象指針恢復為完整的X.

080487ea <_ZThn8_N1X4funcEv>:   # in "X-B vtbl"
_ZThn8_N1X4funcEv():
 80487ea:       83 44 24 04 f8          addl   $0xfffffff8,0x4(%esp)
 80487ef:       eb 01                   jmp    80487f2 <_ZN1X4funcEv>
 80487f1:       90                      nop

080487f2 <_ZN1X4funcEv>:        # in X-A vtbl
_ZN1X4funcEv():
 80487f2:       55                      push   %ebp
 80487f3:       89 e5                   mov    %esp,%ebp
 80487f5:       8b 45 08                mov    0x8(%ebp),%eax
 80487f8:       c7 40 14 01 00 00 00    movl   $0x1,0x14(%eax)
 80487ff:       5d                      pop    %ebp
 8048800:       c3                      ret    

不要過分迂腐,但C#編譯器不參與此級別。 整個類型模型,繼承,接口實現等實際上由CLR處理,更具體地說是CTS(通用類型系統)。 .NET編譯器大多只生成表示意圖的IL代碼,后者由CLR執行,其中所有Vtable處理等都由此處理。

有關CLR如何創建和管理運行時類型的一些細節,以下鏈接將是一個很好的起點。 接下來解釋了MethodTable和Interface Maps。

http://web.archive.org/web/20150515023057/https://msdn.microsoft.com/en-us/magazine/cc163791.aspx

是的,托管語言中只有一個v表,CLR不支持多重繼承。 當您轉換為已實現的接口時,會有一個指針修復。

當嘗試聲明一個COM接口時,這是一個值得注意的問題,該接口本身是從IUnknown之外的另一個接口聲明的。 這篇文章的作者不太了解這個問題。 COM需要為每個接口提供一個單獨的 v表,就像支持MI的編譯器一樣。

vtables是一個實現細節。 沒有正式/必要/預期的實施。 不同的編譯器供應商可以不同地實現繼承

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM