6

I'm trying to undestand some low-level things with virtual table and inheritance.

When you create new class by inheriting two classes and adding new virtual functions, where exactly the vptr will be stored?

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

Suppose, we have the following structs:

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 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 reassemble C, I get this:

   +------+------+------+------+------+------+------+
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 the vptr of C? I can suppose that compiler merge different virtual tables (ex. vptr of A and C), but in that case why sizeof(C) returns sizeof(A) + sizeof(B) + sizeof(alligned_char) + sizeof(vptr)

The struct D : public C {} has the same story - there is no vptr of D.

The compiler I use is msvc 2012 x86.

renzo
  • 311
  • 1
  • 13
  • 1
    why vptr in struct B need 8 bytes? – cartman May 24 '17 at 08:20
  • 1
    @walker I doubt it does. It's probably some padding. – luk32 May 24 '17 at 08:21
  • 3
    Possible duplicate of [How many vptr will a object of class(uses single/multiple inheritance) have?](https://stackoverflow.com/questions/3342035/how-many-vptr-will-a-object-of-classuses-single-multiple-inheritance-have) – Andrew May 24 '17 at 08:21
  • 1
    @walker it's padding to sizeof(double) – renzo May 24 '17 at 08:22
  • 1
    This is all platform- and/or compiler-specific implementation detail. Unless you say what platform and compiler you care about (all I know so far is it seems to be 32-bit), the best you can expect is an essay on possible implementations (and that's probably too broad). Anyway, you can just inspect the assembly output to see what your compiler is doing. – Useless May 24 '17 at 08:38
  • @Andrew B doesn't inherit A – renzo May 24 '17 at 08:45
  • Why would you want another vptr? – curiousguy May 25 '17 at 18:53
  • @Useless Can you cite even one compiler that does it differently? – curiousguy May 25 '17 at 18:54
  • Yes: all 64-bit flat memory model platforms do it differently than your illustration above, because the pointer will be 8 bytes rather than 4. – Useless May 26 '17 at 08:58
  • @Useless I mentioned about the platform – renzo May 26 '17 at 09:04

1 Answers1

4

The compiler has to juggle simplicity, with the fact that the base classes need to exist within the object.

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

So

  • A needs to exist as if it was not derived.
  • B needs to exist as if it was not derived.
  • C has new freedom.

virtual functions from A and B will be patched for the derived class C's implementation. C will add virtual functions to (probably) the existing first element As vtable.

base vtable for A

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

vtable for A in the derived class C

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

vtable for B in the derived class C

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

I think alignment rules are causing the size of C to be padded so the alignment sensitive double is correctly aligned (ensure that an array of C is properly aligned).

The size of B is the size of the vptr (4) and padding to ensure the double is aligned (4) and the size of the double (8)

mksteve
  • 12,614
  • 3
  • 28
  • 50