Memory layout and layout of the C ++ virtual inheritance class
1. Single virtual inheritance
It is only for analysis, but it does not play a major role in practice. The memory layout of the derived class objects related to virtual inheritance is related to the specific compiler.
(1) VS Compiler: No matter whether there are virtual functions or not, it must contain virtual base table pointers. The content in the virtual base table is the offset of the class instance and the relative offset value of the base class instance. If there are virtual functions, the virtual function tables of the base class are separated from the virtual function tables of the derived classes.
In the memory layout, the address ranges from low to high. The order is as follows: virtual function table pointer of the derived class + virtual base class Table pointer + member variable of the derived class + "interval" (4 bytes) + base class virtual function table pointer + base class member variable. The positional relationship between the derived class and the base class instance is exactly the opposite to that of normal inheritance.
Note: The reason for "interval" is that the derived class overrides the virtual function of the base class. If it is not overwritten, This item does not exist. "This Class address" refers to the object (or part of the object) that contains a virtual base class, that is, the address of the directly subclass object on the inheritance chain. This example is relatively simple, is the object address of the derived class. "The address of this class is only different from the pointer address of the virtual base class table". This value is usually-4, 0, and-4, indicating that "this class" has a virtual function table pointer; 0 indicates that the first 4 bytes of the "class" are saved as virtual base table pointers without virtual function table pointers.
Figure 1 VS compiler-single virtual inheritance
(2) gnu gcc Compiler: similar to VS compiler, the difference is that the virtual base-class table and the virtual function table of the derived class are merged. In addition, different offset values can be obtained by addressing the virtual base table pointer to both positive and negative directions, that is, there are two virtual function tables with the same functions. However, in actual application, I don't know whether the virtual base-class table is really useful. I tested it and found that the compiler has been optimized, there is no virtual base class table to address virtual base class instances.
Figure 2 GCC compiler-single virtual inheritance
2. Virtual inheritance of multiple base classes
To add content to a virtual base table, if there are N virtual base classes, there will be N base class instance offset values, plus one offset value for this class instance, that is, N + 1.
Assume that Class A and Class B are inherited by Class C virtualization, and the most complex case (all have virtual functions) is considered, the memory layout of class C objects is as follows:
(VS compiler ):
Class C virtual function table pointer + virtual base class Table pointer + class C member variable + Class A interval (4 bytes) + class A virtual function table pointer + Class A member variable + Class B interval (4 bytes) + Class B virtual function table pointer + Class B member variable.
Note: When the derived class overrides the virtual function of the base class, there is an "interval ". The "interval" is a virtual base class implemented by the virtual function. It may be a sign or used when the function is called. Not very clear.
Figure 3 VS compiler-virtual inheritance of multiple base classes
(GCC compiler ):
Class C virtual function table pointer (including virtual base class table) + class C member variables + class A virtual function table pointer + Class A member variables + Class B virtual function table pointer + Class B member variables.
Compared to the execution, the GCC compiler is used, and the objects in the derived class are smaller. (Figure omitted)
3. Diamond inheritance of virtual inheritance
Here the diamond Inheritance refers to B, C virtual inheritance A, then D ordinary inheritance B, C.
The memory layout of class D Objects is as follows:
(VS compiler)
Class B virtual function table pointer (this virtual function table contains the address of the virtual function exclusive to Class D) + Class B virtual base class Table pointer + Class B member variable + class C virtual function table pointer + class C virtual base class Table pointer + class C member variable + Class D member variable +" interval "+ class A virtual function table pointer + Class A member variable.
Note: If the virtual functions of Class A are not overwritten, there is no "interval ".
Figure 4 VS compiler-diamond inheritance
(GCC compiler)
Merge the virtual function tables of class B and class C with the virtual base table. (Figure omitted)
4. VS compiler, question about "interval"
There is no "interval" for rewriting without virtual functions, so it may be related to virtual functions, that is, to achieve polymorphism, specifically, I used a simple disassembly and debugging (the parent class Pointer Points to the subclass object and calls the virtual function rewritten by the quilt class). I didn't find out where the "interval" was used ", it may need to be used in complex calls. It is unclear at present.
5. Questions about virtual base tables
Through disassembly debugging, it is found that when polymorphism is used, the VS compiler uses the virtual base class table to address the virtual base class address. The GCC compiler did not do this. it tested a relatively simple situation and found that it was optimized. Instead, it did not use the virtual base class table, but directly added a constant to the object address of the derived class, obtain the address of the virtual base instance.
Summary:
1. For A single inheritance, no matter how long the inheritance chain is, the member variables are added by means of superposition until classes (called A) that contain virtual functions exist, vfptr exists in this class. If Class A is the parent class, all its inherited subclasses have A vfptr.
2. For multi-inheritance (including repeated inheritance, that is, the case of superclasses), if there is no virtual function, it is the superposition of the parent class. If there is a virtual function, vfptr exists. In the subclass, the number of vfptr is the same as the number of multi-core parent classes. If the parent class contains vfptr, then, the virtual function in the subclass is integrated with the first parent class with vfptr. The number of vfptr In the subclass is at least 0, that is, all parent classes and superclasses, and no virtual function exists in the subclass.
3. Virtual inheritance: the consciousness of virtual inheritance is to solve the problem of repeated inheritance. After virtual inheritance, it can ensure that there is a copy in the sub-class. The first clear point is, in which subclass is inherited in the virtual mode, a pointer to the virtual base class is added to this subclass. The remaining method is the same as the general inheritance method. Refer to the previous article.
Http://www.cnblogs.com/cswuyg/archive/2010/08/20/1804113.html
C ++ to ensure that the virtual base class constructor is executed only once by the class of the created object
You should know that the virtual base class is designed to prevent problems caused by multi-inheritance. For example, a base class may be inherited several times by the same subclass, with the virtual base class, this base class will not repeat the object memory layout. Then let's look at this sentence again. We can understand it in this way based on the previous description.
Class A // Base class
Class B: public A // B inherits
Class C: public A, B/C inherit A and B. Here, A should be virtual inheritance; otherwise, A will be inherited twice because B inherits
When creating C Object c:
C c
In the case of virtual inheritance, in order to ensure that the virtual base class A is constructed only once, we have defined:
1. When c is created, it will call the constructor initialization of A and the constructor initialization of c. (Corresponding to this sentence:"
Only the constructor of the virtual base class is called and its own Initialization is performed (executed) in the constructor of the derived class of the created object ")
2. B belongs to the direct base class of c. When constructing c, B must be constructed, that is, the constructor or B User-Defined constructor provided by the system to B will be called, but B won't initialize A here. (This is what you asked)
The preceding description is divided into two parts, which does not represent the exact process of construction.
Please explain the virtual inheritance in c ++ to me in plain terms.
C ++ allows multiple inheritance. A class can inherit multiple base classes. For example, Class D inherits B1 and B2, which is no problem. However, if the two base classes B1 and B2 are derived from a common base class B, you will encounter a terrible "diamond" (inheritance relationship ). The problem is that in Class D, the content of Class B inherits two copies, not only occupying more space, there is also a conflict in the name (although it can be accessed through special methods ).
The so-called "virtual inheritance" aims to ensure that, in the case of this "diamond" inheritance, in the final subclass (such as Class D, only one copy of the content inherited from the common base class (such as Class B) is retained, and the content is inherited through different channels (such as B1 and B2.
To be more popular, for example, B's Children B1 and B2 are "close relatives", causing their offspring d to have a duplicate B gene. This will lead to many problems (for example, there may be two types of gender :)). Virtual inheritance aims to solve such problems.
For example, a factory produces some products, including Lamp and Phone, which are combined into a Phone with a Lamp (maybe called a Lamp with a Phone number ), if each product has a serial number, multiple serial numbers appear in the combined product.
Class Product {int id ;}; class Lamp: public Product {}; // Product: idclass Phone: public Product {}; // Product: idclass LampPhone: public Lamp, public Phone {}; // Lamp: id and Phone: id different considering the possibility that different products may be inherited more, virtual inheritance should be considered in inheritance, to avoid the above problems.
Class Product {int id ;}; class Lamp: public virtual Product {}; // Product: idclass Phone: public virtual Product {}; // Product: idclass LampPhone: public Lamp, public Phone {}; // there is only one Product: id