How are vtables implemented in C ++ and C #?

It allows you to have this situation (in C ++, in C # classes A, B have interfaces):

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? 

Does the C # compiler create only one vtable? Does he make any pointer corrections when casting?

+5
c ++ inheritance c # interface vtable
source share
4 answers

Not to be too pedantic, but the C # compiler is not involved in this level. Model of all type, inheritance, interface implementation, etc. In fact, CLR is processed, in particular, CTS (Common Type System) .. NET compilers basically just generate IL code, which is the intention that CLR later executes, where all Vtable processing, etc. Take care.

Detailed information on how the CLR creates and manages runtime types is a good starting point for the next link. At the end, explanations of the methods and interfaces are explained.

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

+2
source share

If I learn this derived version with 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]); } 

It turns out that in C ++ b == a + 1, the structure X is [vtable-X + A] [vtable-B] [magic] [var] checking deeper (nm./a.out), vtable-X + a contains a link to X :: func (as you would expect). when you sent your X to B, it adjusted the pointers so that VTBL functions for B are displayed where the code expects this.

In fact, did you intend to "hide" B :: func ()?

B vtbl looks like binding a link to a "trampoline" to X, which restores the object pointer to full X before calling the "regular" X :: func, which has X + A vtbl.

 080487ea <_ZThn8_N1X4funcEv>: # in "XB 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 XA 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 
+3
source share

Yes, there is only one v-table in a managed language; the CLR does not support multiple inheritance. When clicking on the implemented interface, there is a pointer fix.

This is a noticeable problem when trying to declare a COM interface that is itself declared from another interface outside of IUnknown. The problem is not entirely clear to the author of this article . COM requires a separate v table for each interface, just what the compiler does that supports MI.

+2
source share

vtables is an implementation detail. There is no official / mandatory / expected implementation. Different compiler providers may implement inheritance in different ways.

+1
source share

All Articles