C ++ virtual overlay memory framework

Virtual inheritance memory plans

I'm trying to fully understand what's going on under the hood in memory with virtual inheritance and vTables / vPtrs and what's not.

I have two example code that I wrote and I understand exactly why they work, but I just want to make sure I have the right idea in mind, in the object memory layouts.

Here are two examples in the picture and I just want to know if my idea about memory layouts is 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

+3


source to share


1 answer


The C ++ standard says little about object layout. Virtual function tables (vtables) and virtual base pointers are not even part of the standard. Thus, the question and answers can only illustrate possible implementations.

A quick glance at your drawing seems to show the correct layout.

You may be interested in the following links:

Edit: does it inherit from below Right::a

or Left::a

?



Your test is 2 , Right

and Left

uses a common common parent Top

. Thus, Bottom

there is only one subobject inside Top

, and therefore only one and the same one exists Top::a

.

Interestingly, you included 2 participants a

in your test Right

. It is a

, which is different from a

, inherited from Top

. It is a great member and just has the same name as the other membemr "coincidentally". Therefore, if you have access to a

through Right

, Right::a

hides Top::a

(by the way, also Bottom::Top::a

, Right::Top::a

, Left::Top::a

). In this case, bottom.a means Right :: a, not because of the layout of the object, but because of the localization (and hiding) rules of the name. And it doesn't depend on the implementation: it's standard and portable.

Here's an option 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;
}; 

      

0


source







All Articles