Search code examples
c++virtualmultiple-inheritance

c++ virtual inheritance initialization order


Hi, As you can see the Construction order in the example is: – U1 U2 Y X V2 V1 V3 V4 B1 B2 D

I understand that : U1 U2 Y X were initialized because the V2 is the first direct virtual inheritance to D, and in order to initialize it there is need to initialize these first U1 U2 Y X . After that V2 was initialized , but why V1 is initialized before V3 although there is direct virtual inheritance from V3 .

Please ignore the numbers of the nodes and arrows and notice that red arrow is non virtual inheritance and black arrow is virtual.

Note: original document may be found there.


Solution

  • Here is my understanding of the example. It matches the construction order, so I believe it to be correct. However, I'm not certain.

    First off, the numbers of the arrows are important because they tell you the order in which the base classes are defined. Just using D as an example, the class is defined as so:

    class D : virtual V2, B1, B2, virtual v3 {...}
    

    Given that, my next step is to traverse the graph and put all the classes into depth-first order regardless of whether they are virtual or not. Braces indicate a base class. Parentheses indicate a virtual base class that is already in my class list:

    D {V2 {X {U1, U2}, Y {(U2), (U1)}}, B1 {V1, (V2), V3 {(Y), (U2)}, V4}, B2 {(V4-V1)}, (V3)
    

    To me this says

    • To construct D, first I need V2.
    • V2 needs X, which needs U1 and U2.
    • Next V2 needs Y, which needs U2 and U1, but both are already in my list.
    • Next D needs B1.
    • B1 needs V1, V2, V3 and V4, with V2 already in my list.
    • V3 needs Y and U2, but both are already in my list.
    • Next D needs B2, which needs V4 through V1, all already in my list.
    • Finally, D needs V3, but again, it is already in my list.

    Given that, I'll now remove the redundant base classes, leaving this:

    D {V2 {X {U1, U2}, Y}, B1 {V1, V3, V4}, B2}
    

    The next part is to find the non-virtual base classes and make adjustments to my list.

    • V2 needs X and Y, where Y is virtual, so Y will have to come before X.

    An extra point about this: Given your question, I would expect you to also think that U2 should come before U1 because Y is constructed before X and in Y, U2 is derived first. However, that does not happen. Instead, X's virtual base classes are done in order, then Y, and finally X.

    This adjusts my list to the following:

    D {V2 { {U1, U2}, Y, X}, B1 {V1, V3, V4}, B2}
    

    Finally, B1 is non-virtual, so it needs to come after V1, V3 and V4. This leaves:

    D {V2 { {U1, U2}, Y, X}, {V1, V3, V4}, B1, B2}
    

    Note that B2 is also non-virtual and would need to be considered if it wasn't already last in my list.

    This gives me an order that I am happy with. The only problem is that I am listing derived classes before base classes, and we know that base classes are constructed first. The only two places left where this is an issue are

    • D, which needs to be last.
    • V2, which needs to be after its children.

    So I'll adjust my list to move these two items, V2 after X, and D after B2.

    { { {U1, U2}, Y, X} V2, {V1, V3, V4}, B1, B2} D
    

    Now I'll remove the parentheses and:

    U1, U2, Y, X, V2, V1, V3, V4, B1, B2, D
    

    You can see that this matches the order of constructors in the diagram, and does, in fact match the order called when I build with Visual Studio 2012.