This time we look at the virtual inheritance of the rhombic structure. The introduction of virtual inheritance is to solve the problem of the inheritance system of complex structure. In the last article we discussed the virtual inheritance with a simple inheritance structure, just to pave the ground.
Let's look at these classes first, which is a classic diamond-like inheritance structure. C100 and C101 share the same parent class C041 through virtual inheritance. C110 from C100 and C101 to multiple inheritance.
struct C041
{
C041() : c_(0x01) {}
virtual void foo() { c_ = 0x02; }
char c_;
};
struct C100 : public virtual C041
{
C100() : c_(0x02) {}
char c_;
};
struct C101 : public virtual C041
{
C101() : c_(0x03) {}
char c_;
};
struct C110 : public C100, public C101
{
C110() : c_(0x04) {}
char c_;
};
Run the following code:
PRINT_SIZE_DETAIL(C110)
The results are:
The size of C110 is 16
The detail of C110 is 28 c3 45 00 02 1c c3 45 00 03 04 18 c3 45 00 01
We can draw the memory layout of an object as in the previous article.
|C100,5 |C101,5 |C110,1 |C041,5 |
|ospt,4,11 |m,1 |ospt,4,6 |m,1 |m,1 |vtpt,4 |m1 |
(Note: In order not to break the line, I used the abbreviation.) The OSPT represents the offset value pointer, m represents the member variable, and the VTPT represents the virtual table pointer. The first number is the size of the area, that is, the number of bytes. Only the offset value pointer has a second number, and the second number is the size of the offset value that the offset pointer points to. )
You can see that there is only one C041 in the memory layout of the object, that is, there is only one part of the grandfather class, and it is placed on the last side. This is the diamond inheritance. In contrast to the previous discussion, we can see that without the virtual inheritance mechanism, there will be two parts of the C041 in the memory layout of the C041 object, which is called the V-type inheritance. The corresponding object layout is: c041+c100+c041+c101 +c110. In the V-type inheritance is not directly from the C110, that is, grandson of the class, directly into the C041, that is, grandfather class. Because there are two of them in the layout of the objects, one from the C100 and one from the C101. The compiler in the resolution will have ambiguity, it does not know the transformation after the actual use of the entity. Although it can be resolved by first transforming into a parent class and then transforming into a grandparent class. However, when using this method, if the contents of the member variable of the grandparent class are rewritten, runtime will not synchronize the state of the two grandparent entities, so there may be semantic errors.