Understanding vtable in derived classes

I am trying to uncover some low level things with virtual table and inheritance.

When you create a new class, inheriting two classes and adding new virtual functions, where exactly is vptr stored?

It seems to me that in this case the compiler performs some "vptr optimization". And I'm trying to figure it out.

Suppose we have the following structures:

struct A { int a; virtual void fa(); }; struct B { double b; virtual void fb(); }; struct C : A, B { char c; virtual void fa(); virtual void fb(); virtual void fc(); }; 

In the case of x86 and align = 4, A and B in memory will look like this:

  +------+------+ A: | vptr | a | +------+------+ sizeof(A) = 4 + 4 = 8 +------+------+------+------+ B: | vptr | b | +------+------+------+------+ sizeof(B) = 8 + 8 = 16 

But when I try to build C , I get the following:

  +------+------+------+------+------+------+------+ C: | vptr | a | vptr | b | c | +------+------+------+------+------+------+------+ but sizeof(C) = 32  ; (C*)&c; // 0x100 (B*)&c; // 0x108 (A*)&c; // 0x100 &c.a; // 0x104 &c.b; // 0x110 &c.c; // 0x118 

So where is vptr C ? I can assume that the compiler joins different virtual tables (e.g. vptr from A and C ), but in this case, why sizeof(C) returns sizeof(A) + sizeof(B) + sizeof(alligned_char) + sizeof (vptr)

struct D : public C {} has the same story - no vptr D

I am using the msvc 2012 x86 compiler.

+5
source share
1 answer

The compiler should juggle simplicity, since base classes must exist inside an object.

 +------+---------+----+ | A | B | C | +------+---------+----+ 

So,

  • A must exist as if it was not received.
  • B must exist as if it were not received.
  • C has a new freedom.

virtual functions from A and B will be fixed to implement a derived class C. C will add virtual functions (possibly) to the existing first element of A vtable.

base vtable for A

 +------+ | A:fa | +------+ 

vtable for A in derived class C

 +------+ | C:fa | // implemented by derived class. +------+ | C:fb | // any calls to fb need to be sent to `C` implementation +------+ | C:fc | // any calls to fc can be overridden by vtable. +------+ 

vtable for B in derived class C

 +------+ | C:fb | // overridden, but no need to add fc, fa to this table. +------+ 

I think alignment rules cause the C size to be padded, so the double sensitive alignment element is correctly aligned (make sure the C array is correctly aligned).

Size B is the size of vptr (4) and vptr to ensure double (4) alignment and double (8) size

+4
source

Source: https://habr.com/ru/post/1268162/


All Articles