<In-depth exploration of the C ++ object model> (Simplified Version)
(Do not read this book)
The last time I saw this book was a year ago (MR. Hou's traditional version). It took me a week to finish reading the book, it also solved many of my questions about C ++. This time, I finally saw the simplified version. It also took me a week, and it may be a success, I am familiar with it two times (or maybe it is my close affection for simplified text). I also found some problems while thinking about the problem.
One snake foot, p84,
Class X {};
Class Y: Public Virtual X {};
Class Z: Public Virtual Z {};
Class A: Public X, pubic Z {};
Written in the book
In fact, this size is affected by three factors,
1) additional burden on the language itself ,.
2) the compiler optimizes the arch mentioned in special cases ..
3) alignment restrictions ..
Mr. Hou himself added the following:
At that time, the figure was "puzzling". For Y or Z, since it has been inherited from X Virtual, it has an additional 4 bytes overhead, that is to say, it is no longer an empty class, and the 1 char byte for Y (z) is empty won't work, and from the perspective of Lippman's intention,
"2) for the optimization processing provided by the compiler in special circumstances, the 1 byte subobject of virtual base class X also appears on class Y and Z, traditionally, it is placed at the end of the fixed (unchanged) part of the derived class. "p88 explains," It stores data directly in every class object, this applies to the inherited nonstatic data member (whether virtual or nonvirtual base class ",
Therefore, the figure I understand should be as follows:
That is to say, the members of the parent class directly inherit from the Child class, but for virtual inheritance, they need to be accessed through an indirect layer (represented as a pointer in some form, this idea is verified again in section 3.5 (Virtual inheritance) (see p121), which also mentions, optimization of the empty base class usually places the empty base class at the beginning of the derived class object, so that no extra space is consumed. It can also be analyzed that the structure of a is as follows: (in this book, Mr. Hou did not give this picture)
Sizeof (a) has 12 bytes. When empty base class is optimized, it has 8 bytes.
Snake foot II, p234,
Mr. Hou changed the order of Lippman (something that occurred during the analysis), and he decided to "this is the opposite order of the ctor", which is not subjective, "2. The dtor function is being executed now. That is to say, the vptr will be reset before the programmer's code is executed.
Struct B {};
Struct D1: virtual public B {};
Struct D2: virtual public B {};
Struct D: Public D1, D2 {};
Ctor: (see the ctor of vertex3d)
D ()
{
If (_ most_derived)
This-> B ();
This-> d1 (false), this-> D2 (false );
Vptr = D: vptr;
// Usercode
}
File: // The Compiler expands the dtor as follows, in reverse order.
~ D ()
{
Vptr = D: vptr ;//**//
// User code...
This-> ~ D2 (false), this ~ D1 (false );
If (_ most_derived)
This-> ~ B ();
}
Isn't that what Lippman means (see the order from 1 to 5 in the book )? Mr Hou's so-called custom order is hard to understand.
When D is destructed, first set vptr = D: vptr, then execute the Destructor body, and then set D2: vptr, D1: vptr, and finally B :: vptr, which is easy to understand.
Mr. Hou indicated at that "if the object contains a vptr, it is now reset to point to the virtual table of the appropriate base class", that is, the vptr is set to skip, yes ~ D () after the user code is executed (// ** // The line marked is not executed), set vptr to D2: vptr, and then execute ~ D2 () function body ~ Set vptr to D1: vptr at the end of D2 (), and then execute ~ D1 (), odd!
This is the vptr of another unrelated class, but there is no parent-child relationship between them. I personally think that the order set by Mr. Hou is too theoretical, and the Lippman method is based on reality.
Snake foot 3: p263
Class Point
{
Public:
Virtual ~ Point (){}
};
Class point3d: Public point
{
};
Point * PTR = new point3d [10];
For (int ix = 0; ix <elem_count; ++ IX)
{
Point * P = & (point3d *) PTR) [ix];
Delete P;
}
Mr. Hou changed it:
For (int ix = 0; ix <elem_count; ++ IX)
{
Point3d * P = & (point3d *) PTR) [ix];
Delete P;
}
Obviously, the virtual destructor do not need to specify the explicit type. Even if the type is specified, it is all converted to (p-> vptr [1]) (p) by resolve ), it will not improve the performance.
Finally, Lippman believes that
Point * PTR = new point3d [10];
Delete [] PTR;
"This is not a good idea at all (For details, refer to p263)." Maybe at that time, it wasn't ^ _ ^, But I tested the results on vc6, it is completely correct, so you can use it with confidence (I have not tested other compilers. If you are interested, try it on your own ).
The day of the festive season, written in a rush. Do not answer your fears. Sorry.