Turn from: http://blog.csdn.net/littlehedgehog/article/details/5442430
This article mainly explains the virtual inheritance of C + + object memory distribution problem, which also leads to dynamic_cast and static_cast essential difference, virtual function table format, and some of the most C + + programmers are specious concepts. See here (by Edsko de Vries, January 2006)
Warning: This article is the introduction of C + + technical articles, assuming that readers have a more in-depth understanding of C + +, but also need some assembly knowledge.
In this article we will illustrate the object memory layout for the GCC compiler for multiple inheritance and virtual inheritance. Although in an ideal use environment, a C + + programmer does not need to understand the internal implementation details of these compilers, in fact, the various implementation details of the compiler for multiple inheritance (especially virtual inheritance) have more or less implications for our C + + code (e.g. downcasting pointer , pointers to pointers, and invocation order of virtual base class constructors. If you can understand how multiple inheritance is implemented, then you can foresee these effects yourself and then be able to deal with them well in your code. Moreover, if you are very concerned about the efficiency of the Code, it is also helpful to correctly understand the virtual inheritance. Finally, this hack process is very interesting oh:
Multiple Inheritance
First, let's consider a very simple (non-virtual) multiple inheritance. Take a look at the C + + class hierarchy below.
1 class top
2 {
3 Public:
4 int A;
5};
6
7 class left: public Top
8 {
9 Public:
Ten int b;
11};
12
class right: Public Top
14 {
Public :
int C;
17};
18
class Bottom: Public left, public right
20 {
Public :
int D;
23};
24
expressed in UML as follows:
Note that the top class is actually inherited two times (this mechanism is called repeated inheritance in Eiffel), which means that there are actually two a properties in a bottom object (attributes, which can go through bottom.) Left::a and bottom. Right::a access).
So left, right, bottom in the memory how to distribute it. Let's take a look at the simple left and right memory distributions:
[The layout of the right class is the same as left, so I'm not drawing anymore.] Hedgehog
Note that the first attribute of the class above is inherited from the top class, which means the following two assignment statements:
1 left* left = new left ();
2 top* top = left;
The left and top actually point to two identical addresses, and we can use the right object as a top object (as well as a top object). But what about the Botom object? GCC is handled this way: (by Orc without virtual inheritance)
But now what happens if we upcast a bottom pointer?
1 bottom* Bottom = new Bottom ();
2 left* left = bottom;
This piece of code is running correctly. This is because the memory layout chosen by GCC allows us to treat bottom objects as left objects, which are exactly the same. But what if we upcast the bottom object pointer to the right object?
1 right* right = bottom;
If (note, if by ORC) we want to make this code work properly, we need to adjust the pointer to the appropriate part of the bottom.
By adjusting, we can use the right pointer to access the bottom object, when the bottom object behaves as if it were the object. But the bottom and right pointers point to different memory addresses. Finally, we consider the following:
1 top* top = bottom;
Well, there is no result, this statement is in fact ambiguous (ambiguous), the compiler will be an error: Error: "Top" is a ambiguous base of ' Bottom '. In fact, these two ambiguous possibilities can be distinguished by the following statement:
1 top* topl = (left*) bottom;
2 top* topr = (right*) bottom;
After these two assignment statements are executed, theTOPL and left pointers will point to the same address, and TOPR and right will also point to the same address .
Virtual Inheritance
To avoid multiple inheritance of the top class above, we must virtual inherit class top.
1 class top
2 {
3 public :
4 int a;
5 };
6
7 class left:virtual public top
8 {
9 public :
10 int b;
11 };
12
13 class right:virtual public top
14 {
15 Public :
16 int c;
17 };
18
19 class Bottom:public left, public right
20 {
21 public :
22 int D
23 };
24
The above code will produce a class hierarchy diagram (in fact, this may be exactly the way you want to inherit the inheritance).
This class-level diagram is much simpler and clearer for programmers, but it's a lot more complicated for a compiler. Let's use the bottom memory layout as an example, it might be like this: (note, is possible by ORC)
The advantage of this memory layout is that its beginning (left) and left layouts are exactly the same, and we can easily access a bottom object through a left pointer. But let's think about right:
1 right* right = bottom;
What address should we assign to the right pointer? Theoretically, with this assignment, we can use this right pointer as a pointer to a proper object (now pointing to bottom). But in reality it is unrealistic. A real right object memory layout and bottom object is completely different, so in fact we can not use this upcasted bottom object as a real right object. Moreover, there is no room for improvement in the design of our layout. Here we'll look at how the memory is actually distributed, and then explain why it's so designed.
(The offset of the virtual base offset dummy class part offset by ORC from the start part of the object)
There are two points in the above picture that should be noted. The 1th is that the order in which members are distributed in a class is completely different (actually, quite the opposite). 2nd, the class adds a vptr pointer, which is inserted into the class by the compiler during compilation (if virtual inheritance is used when the class is designed, the virtual function produces the associated vptr). At the same time, the related pointers are initialized in the constructor of the class, which is also the work done by the compiler. The vptr pointer points to a "virtual table". Each virtual base class in a class will have a vptr pointer corresponding to it. In order to show you the virtual table function, consider the following code.
1 bottom* Bottom = new Bottom ();
2 left* left = bottom;
3 int p = left->a;
The second assignment statement makes the left pointer point to the same starting address as bottom (that is, it points to the "top" of the bottom object). Let's consider the assignment statement for the third article.
1 movl left,%eax #%eax = left
2 movl (%eax),%eax #%eax = left . vptr. Left
3 movl (%eax),%eax #%eax = VIRTUAL BASE OFFSET&NBSP
4 addl left,%eax #%eax = left + virtual base offset
5 movl (%eax), %eax #%EAX = LEFT.A
6 movl %eax, p # p = left.a
Summary, we use the left pointer to index (find) virtual table, and then virtual The offset (virtual base offset , vbase) of the to the virtual base class is obtained in the table, and then the offset is added to the left pointer So that we get the start address of the top class in the bottom class. from the above illustration, we can see that for the left pointer, its virtual base offset is 20 if we assume bottom