1

I'm trying to get a better understanding how virtual inheritance works in practice (that is, not according to the standard, but in an actual implementation like g++). The actual question is at the bottom, in bold face.

So, I built myself a inheritance graph, which has among other things, these simple types:

struct A {
  unsigned a;
  unsigned long long u;
  A() : a(0xAAAAAAAA), u(0x1111111111111111ull) {}
  virtual ~A() {}
};

struct B : virtual A {
  unsigned b;
  B() : b(0xBBBBBBBB) {
    a = 0xABABABAB;
  }
};

(In the whole hierarchy I also have a C: virtual A and BC: B,C, so that the virtual inheritance makes sense.)

I wrote a couple of functions to dump the layout of instances, taking the vtable pointer and printing the first 6 8-byte values (arbitrary to fit on screen), and then dump the actual memory of the object. This looks something like that:

Dumping an A object:

actual A object of size 24 at location 0x936010
vtable expected at 0x402310 {
          401036,          401068,          434232,               0,               0,               0,
}
1023400000000000aaaaaaaa000000001111111111111111
[--vtable ptr--]

Dumping a B object and where the A object is located, which is indicated by printing a lot As at the respective position.

actual B object of size 40 at location 0x936030
vtable expected at 0x4022b8 {
          4012d2,          40133c,        fffffff0,        fffffff0,          4023c0,          4012c8,
}
b822400000000000bbbbbbbb00000000e022400000000000abababab000000001111111111111111
                                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  (offset: 16)

As you can see, the A part of B is located at an offset of 16 bytes to the start of the B object (which could be different if I had instantiated BC and dyn-casted it to a B*!).

I would have expected the 16 (or at least a 2, due to alignment) to show up somewhere in the table, because the program has to look up the actual location (offset) of A at runtime. So, how does the layout really look like?


Edit: The dump is done by calling dump and dumpPositions:

using std::cout;
using std::endl;

template <typename FROM, typename TO, typename STR> void dumpPositions(FROM const* x, STR name) {
  uintptr_t const offset {reinterpret_cast<uintptr_t>(dynamic_cast<TO const*>(x)) - reinterpret_cast<uintptr_t>(x)};
  for (unsigned i = 0; i < sizeof(FROM); i++) {
    if (offset <= i && i < offset+sizeof(TO))
      cout << name << name;
    else
      cout << "  ";
  }
  cout << "  (offset: " << offset << ")";
  cout << endl;
}
template <typename T> void hexDump(T const* x, size_t const length, bool const comma = false) {
  for (unsigned i = 0; i < length; i++) {
    T const& value {static_cast<T const&>(x[i])};
    cout.width(sizeof(T)*2);
    if (sizeof(T) > 1)
      cout.fill(' ');
    else
      cout.fill('0');
    cout << std::hex << std::right << (unsigned)value << std::dec;
    if (comma)
      cout << ",";
  }
  cout << endl;
}
template <typename FROM, typename STR> void dump(FROM const* x, STR name) {
  cout << name << " object of size " << sizeof(FROM) << " at location " << x << endl;
  uintptr_t const* const* const vtable {reinterpret_cast<uintptr_t const* const*>(x)};
  cout << "vtable expected at " << reinterpret_cast<void const*>(*vtable) << " {" << endl;
  hexDump(*vtable,6,true);
  cout << "}" << endl;
  hexDump(reinterpret_cast<unsigned char const*>(x),sizeof(FROM));
}
2
  • It would be nice/helpful to see the code which does the 'dump'. Commented Mar 30, 2012 at 17:40
  • @gbulmer: There you go. Although I don't think its much help. Commented Mar 30, 2012 at 17:45

1 Answer 1

1

The answer is actually documented here, in the Itanium ABI. In particular section 2.5 contains the layout of the virtual table.

Sign up to request clarification or add additional context in comments.

3 Comments

That was my second guess, but as you can see in the dump, B has only 16 byte (besides the A part). The first 8 bytes are the vptr, while the second 8 bytes are the b integer member (aligned). At least, that's how I read it. I would expect the offset 16 or the address 0x4022c8 (== 0x4022b8 + 16) somewhere. I'm going to have a look at your link now, however.
The virtual table description (category 3) has a lot of caveats. Do you know of a grammar description for this?
the link is broken, this is why it is needed to not put only link but also the interesting part of the content ^^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.