9

Virtual Inheritance Memory Layouts

I am trying to fully understand what is happening under the hood in the memory with virtual inheritance and vTables/vPtrs and what not.

I have two examples of code I have written and I understand exactly why they work however I just want to make sure I have the right idea in my mind, of the object memory layouts.

Here are the two examples in a picture, and I just wish to know if my idea of the memory layouts involved are correct.

Example 1:

class Top { public: int a;  };
class Left : public virtual Top {  public: int b; };
class Right : public virtual Top { public: int c; };
class Bottom : public Left, public Right { public:  int d; };

enter image description here

Example 2:

Same as above, but with:

class Right : public virtual Top {
public:
    int c;
    int a;  // <======= added this
};

enter image description here

Christophe
  • 68,716
  • 7
  • 72
  • 138
Dominic Farolino
  • 1,362
  • 1
  • 20
  • 40
  • 1
    A good place to start is [the itanium abi](https://mentorembedded.github.io/cxx-abi/abi.html) since this is all implementation specific – Mgetz Jun 16 '15 at 15:12
  • @Mgetz A little unsure why you would suggest starting with the Itanium ABI, when either the x86 or amd64 ABI is statistically more likely to be pertinent to the original question - or maybe I'm missing something in the question that identified an Itanium platform...? – twalberg Jun 16 '15 at 15:23
  • 3
    @twalberg because the itanium ABI is used even on X86-64 for c++ as the standard ABI – Mgetz Jun 16 '15 at 16:31
  • possible duplicate of [Virtual tables and memory layout in multiple virtual inheritance](http://stackoverflow.com/questions/11603198/virtual-tables-and-memory-layout-in-multiple-virtual-inheritance) – Suma Jun 17 '15 at 14:15
  • Your question seems contradicting: should `Top` be polymorphic? – curiousguy Jul 14 '15 at 12:22
  • @Dominic, In your `Example 2` shouldn't `Right::a` appear after `Right::c` in the bottom class layout ? – infinite loop Aug 23 '17 at 04:23

1 Answers1

1

The C++ standard doesn't say much about the object layout. Virtual function tables (vtables) and virtual base pointers are not even part of the standard. So the question and the asnwers can only illustrate possible implementations.

A quick look on your drawing seems to show a correct layout.

You could be interested in these further references:

Edit: Does Bottom inherit Right::a or Left::a ?

In your test 2, Right and Left share the same common parent Top. So there is only one subobject Top within Bottom, and consequently, there is only one and the same Top::a.

Interestingly, you've introduced in your test 2 a member a in Right. This is an a which is different from the a inherited from Top. It's a distinct member, and just has the same name as another membemr "by coincidence". So if you access a via the Right, Right::a hides the Top::a (which is by the way also the Bottom::Top::a, the Right::Top::a, the Left::Top::a). In this case, bottom.a means the Right::a, not because of the object layout, but because of the name loockup (and hiding) rules. And this is not implementation dependent: it's standard and portable.

Here a variant for your test 2 to demonstrate the situation:

int main() {
    Bottom bottom; 
    bottom.a = 7; 
    cout << bottom.Top::a << endl << bottom.Left::Top::a << endl;
    cout << bottom.Right::Top::a << endl << bottom.Left::a << endl;
    cout << bottom.Right::a << endl <<endl;
    bottom.Right::a = 4; 
    bottom.Left::a = 3; 
    cout << bottom.Top::a << endl << bottom.Left::Top::a << endl;
    cout << bottom.Right::Top::a << endl << bottom.Left::a << endl;
    cout << bottom.Right::a << endl <<endl;

    cout << "And the addresses are: " << endl; 
    cout << " Bottom:       " << (void*)&bottom << endl; 
    cout << " Top:          " << (void*)static_cast<Top*>(&bottom) << endl;
    cout << " Left:         " << (void*)static_cast<Left*>(&bottom) << endl;
    cout << " Right:        " << (void*)static_cast<Right*>(&bottom) << endl;
    cout << " Top::a:       " << (void*)&bottom.Top::a << endl;
    cout << " Left::Top::a: " << (void*)&bottom.Left::Top::a << endl;
    cout << " Right::Top::a:" << (void*)&bottom.Right::Top::a << endl;
    cout << " Left::a:      " << (void*)&bottom.Left::a << endl;
    cout << " Rigth::a:     " << (void*)&bottom.Right::a << endl;
}; 
Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Thank you very much. Question though, regarding the Bottom's layout in Test 2 - Does `Bottom` inherit only `Right::a` since its the most recently overrided, or does it inherit both, and use some logic to figure out which one should be used as `bottom.a`? Thanks a lot – Dominic Farolino Jun 17 '15 at 11:59
  • @DomFarolino I've edited my answer to clarify this aspect. – Christophe Jun 17 '15 at 17:56
  • Ahh Ok I knew that declaring `Right::a` would make `Bottom.a` = `Right::a` is because its the most recently overridden attribute. Consequently, `Bottom.Top::a`, `Bottom.Right::Top::a`, and `Bottom.Left::Top::a` are different from `Bottom.a` and `Bottom::Right::a`, however I didn't know if this was solely because of name lookup or if this had to do with memory layout. I will check out your example when I can – Dominic Farolino Jun 17 '15 at 18:14
  • 1
    @DomFarolino Only virtual functions can be overridden. – curiousguy Aug 06 '15 at 03:51
  • @curiousguy True, would redefined be a better term to describe this behavior? – Dominic Farolino Aug 06 '15 at 13:27
  • 1
    @DomFarolino Hiding of data members? – curiousguy Aug 06 '15 at 16:12
  • Does the abstract base class memory model still hold for c++11, c++14, and c++17 that's coming up? I'm curious if the backwards compatibility with COM interfaces will be broken at some point with c++. – Rethipher Nov 10 '16 at 16:44
  • @justthom8 the object model is still the same. However, as pointed out in the answer: the memory layout is implementation dependent. So the question sould rather focus on compiler versions. Nevertheless I wrote this answer doing some fact checking on c++11 compilers. I'd doubt that there were fundamental changes on these fundamental aspects in the meanwhile. – Christophe Nov 10 '16 at 17:28