C + + multiple inheritance and virtual inheritance object model, efficiency analysis _c language

Source: Internet
Author: User
Tags inheritance object model

One, polymorphic

C + + polymorphism is implemented through inheritance and dynamic binding. Inheritance is the inheritance and sharing of code or function, which is external, formal and easy to understand from the point of view of language. Dynamic binding is to guarantee the occurrence of polymorphism from the bottom of the language--in the runtime, the function of the virtual function is determined according to the base class pointer or the real object type that the reference points to. Through single inheritance with virtual functions, we can understand the concept of inheritance, the distribution mechanism of object model and the occurrence of dynamic binding, that is, we can understand the idea of polymorphism completely and completely. To support polymorphism, language implementations must pay an extra price in time and space (after all, there is no free dinner, not to mention the compiler has no feelings):

1, the class is implemented with the addition of virtual table, used to store the virtual function address;
2, the Class object adds the pointer vptr to the virtual function table to provide the runtime link;
3, in the class inheritance level of the constructor repeatedly set the initial value of vptr, to expect the pointer to the corresponding class of virtual table;
4, repeat the initial value of vptr in the destructor of class inheritance hierarchy;
5. When polymorphic occurs (the base class pointer calls virtual functions), a corresponding function entity is called through vptr and virtual table tables, adding a layer of indirection.
The 1th and 22 points are the spatial costs of polymorphism, and the latter three points are the cost of time efficiency.

Second, multiple inheritance and virtual inheritance

Multiple inheritance has multiple base classes, as opposed to single inheritance, which provides a "natural polymorphic" form. In single inheritance, the base class and derived classes have the same memory address, and transitions between them are naturally not required by the compiler. However, if there are no virtual functions in the base class and in the derived class, the natural polymorphism of a single inheritance is broken. In this case, the conversion of the derived class to the base class requires the compiler's intervention to adjust the this pointer address. The object model for multiple inheritance is more complex than a single inheritance, rooted in the "unnatural" relationship between the derived class objects and its second or subsequent base class objects, as can be seen from the object model below. The unnatural polymorphism between the derived class and the base class raises a serious problem (also exists in virtual inheritance): The conversion between the derived class and the second or subsequent base class (whether it is a direct conversion between objects or through the virtual that they support) function mechanism to do the conversion) you need to adjust the address of this pointer so that it points to the complete correct class object.
Virtual inheritance is a mechanism by which the class indicates that it wants to share the state of the virtual base class, and the virtual base class has only one entity in the derived hierarchy. Compared with multiple inheritance, the difficulty of virtual inheritance is to recognize the same object part and maintain the polymorphic relationship between the base class and the derived class. Typically, the compiler splits an object into a invariant local and a shared part when implementing virtual inheritance. Invariant local data, regardless of subsequent derivation, always has fixed offset, so this part of the data can be directly accessed. As for the shared part, it shows the virtual base class Subobject. This part of the data, whose position will vary with each derivation, can only be accessed indirectly. The difference between the implementations of the compilers is that the indirect access methods are different. The general strategy is to arrange the invariant part of the derived class first, and then build the shared part. Virtual inheritance of unnatural polymorphic relationships between base class and derived class requires that the this pointer address be adjusted when converting between them. Virtual inheritance brings additional burdens and model complexity due to the support of the fictitious base class.

Three, multiple inheritance and virtual inheritance object model

The essence of complex and inefficient inheritance of multiple inheritance and virtual inheritance is the difference of memory distribution of object model, which can be seen from the second part. The following example compares the object model for common single inheritance, multiple inheritance, and virtual inheritance. What needs to be explained is that the C + + standard does not enforce the order relationship between the base class members and the derived class member, which can theoretically be freely arranged, but in fact most compilers have a base class membership in the front, except for virtual inheritance. The following is also the strategy, with Vptr as the first member of the class.

The base class Base1, Base2, and derived class Derivedsingle, Derivedmulti classes are defined as follows:

Class Base1
{public
:
  Base1 (void);
  ~base1 (void);
  Virtual Base1* clone () const;
Protected:
  float data_base1;
Class Base2
{public
:
  Base2 (void);
  ~base2 (void);
  virtual void mumble ();
  Virtual base2* clone () const;
Protected:
  float Data_base2;
Class Derivedsingle:public Base1
{public
:
  derivedsingle (void);
  Virtual ~derivedsingle (void);
  Virtual derivedsingle* clone () const;
PROTECTD:
  float data_derivedsingle;
Class Derivedmulti:p ublic Base1, public Base2
{public
:
  derivedmulti (void);
  Virtual ~derivedmulti (void);
  Virtual derivedmulti* clone () const;
Protected:
  float Data_derivedmulti;

The object model is the same as the virtual inheritance and the single inheritance class structure, except that the inheritance is changed to virtual inheritance.

Single Inheritance:

Multiple inheritance:

Virtual Inheritance:

In order to ensure the correctness of the memberwise copy (otherwise the base class child object is copied to the derived class), C + + guarantees the "base class child object is in the derived class".

The single Inherited object model presents a form of "natural polymorphism", and the conversion between the base class and the derived class is naturally simple. However, multiple inheritance has multiple base classes, an object has multiple vptr pointers, and a transformation between a second or subsequent base class and a derived class requires an address adjustment to point to the complete base class child object.

In virtual inheritance, to remember and share a virtual base class, you need to add a pointer to the base class in the class. As you can see from the virtual Inheritance object model above, although there is the same class hierarchy as single inheritance, virtual inheritance breaks the "natural polymorphic" form of single inheritance, and transformations between base classes and derived classes need to adjust the address of this pointer. In the case of virtual multiple inheritance, the conversion between the virtual base class/successor base class and the derived class requires this pointer address adjustment.

General rule, multiple inheritance invokes the derived class virtual function by pointing to a pointer to "second or subsequent base class", and the "necessary this pointer adjustment" operation associated with it must be completed during the execution period. That is, the size of the offset, and the small piece of code that the offset adds to this pointer, must have the compiler inserted somewhere. In order to implement this pointer adjustment to introduce the thunk technique, the so-called thunk is a small piece of assembly code that adjusts the this pointer with the appropriate offset value and jumps to the virtual function. Thunk technology allows virtual table slot to continue to contain a simple pointer, so multiple inheritance does not require any additional space burden. The address in slots can point directly to the virtual function or to a related thunk (if you need to adjust the this pointer). The second additional burden of adjusting this pointer is that, because of two different possibilities: (1) invoked via derived class (or first base class), (2) by the second (or subsequent) base class, the same function in virtual Multiple slots may be required in the table. and the virtual function table in the second or subsequent base class holds the Thunk code address.

Iv. efficiency

Through the analysis of the third part above, the complex object model is inherited by the multiple inheritance and the virtual inheritance object model, which leads to the low efficiency of the member access, which is shown in two aspects: the vptr of the object construction and the adjustment of this pointer. The efficiency comparisons for multiple inheritance situations are as follows:

Situation Vptr Set Data member access Virtual Function member access Efficiency analysis
Single Inheritance No vptr No pointer/reference/object access efficiency is the same Direct access High efficiency
Single inheritance A pointer/reference/object access efficiency is the same Access through vptr and vtable The introduction of polymorphism brings about the reduction of efficiency such as setting vptr and indirect access virtual functions.
Multiple inheritance Times pointer/reference/object access efficiency is the same Through vptr and vtable access, you need to adjust this pointer through second or subsequent base class pointers In addition to a single inheritance efficiency reduction scenario, the Adjust this pointer also leads to reduced efficiency
Virtual inheritance Times Object/pointer/application access less efficient Accessing the virtual base class requires that the this pointer be adjusted through VPTR and vtable access In addition to a single inheritance efficiency reduction scenario, the Adjust this pointer also leads to reduced efficiency

data member access in polymorphism

The key to investigating the efficiency of data member access for several inheritance scenarios in polymorphism is whether the offset position of the members can be determined at compile time. If the accessed member can determine the offset position at compile time, there is no additional burden.

Theoretically, for the inheritance type above, access through class objects is as efficient as the position of the member in the class can be determined at compile time. Access through references or pointers, except in one case, the inheritance type efficiency is exactly the same. The exceptions are: accessing the data members of the virtual base class through pointers and references. Because the virtual base class has varying offset positions at different inheritance levels, and cannot determine the true type of pointer to object by pointer or reference type, the compilation period cannot determine the offset location and can only be determined at run time through type information.

In fact, specific inheritance (non-virtual inheritance) does not increase the additional space or access time, but the "indirection" of virtual inheritance suppresses the optimization ability to "move all operations to the cache", even though the compiler accesses the class object as if it were a pointer (currently, The compiler is not able to recognize that access to "inherited data member" is through a non polymorphic object, and therefore does not require indirect access to the execution period, and the efficiency is worrying. However, the indirect nature does not seriously affect the efficiency of the implementation of the program, and the efficiency of different types of inheritance is not very significant. In general, the most effective form of virtual base class is an abstract virtual base class with no data members.

function member access in polymorphism

In C + +, the nonmember/static Member/nonstatic member functions are converted to the exact same form (through managling naming), so they are all the same.

If you call a virtual function by reference and pointer, the efficiency will be reduced, which is determined by the C + + polymorphism property. The invocation of virtual functions in multiple inheritance and virtual inheritance is less efficient than single inheritance. This can be clearly seen from the table above: this pointer is tuned (for example, through the thunk technique) and multiple initialization of the vptr. Of course, keep in mind that accessing virtual functions through objects is as efficient as accessing non-virtual member functions. In the case of calling a virtual function without requiring polymorphism, the function entity can be explicitly called: Class Name:: Function name, suppressing unnecessary repetitive invocation operations due to virtual mechanisms.

This pointer address adjustment
this pointer adjustment in multiple inheritance and virtual inheritance reduces the efficiency of these two types of inheritance and should be vigilant when programming. The common situations where you need to adjust the this pointer are listed below:

1. The new derived class calls the derived class virtual destructor to the second (successor) base class pointer or through the second (successor) base class

The address of the derived object must be adjusted to point to the Base2 Subobject object. When you delete an object that the base class points to, you must adjust it again to point to the starting address of the derived object, but this adjustment can only be completed during the execution period, and the object class type that the pointer points to cannot be determined at compile time.

Next time you see this, don't be curious: pBase2 is not equal to pderived.

derived* pderived = new Derived;
base2* pBase2 = pderived; Base2 is the second base class of derived
pBase2!= pderived;    Both ranges

2. Calling a virtual function owned by a second or subsequent base class by a derived class pointer

If you want to call correctly the derived class pointer must be adjusted at compile time to point to the successor base subobject to call the correct virtual function. As you can see from the above model diagram: If you call the Mumble function through a derived class pointer, and the Mumble function exists only in the virtual function table of the successor class, you must adjust it.

3, subsequent base class pointer call returns the virtual function of derived class type and assigns to another successor base class pointer

Examples are as follows:

base2* PB1 = new Derived;  The adjustment pointer points to the BASE2 clss child object
base2* PB2 = Pb1->clone ();//PB1 is adjusted to the address of the derived object, produces a new object, adjusts the object pointer to the BASE2 base class child object again, assigns value to PB2.

Remember: The Base class pointer must point to a complete object or child object that is the same as its own type, and a situation that does not satisfy this condition requires an adjustment to this pointer.

Detailed knowledge please refer to: "Inside the C + + Object Model".

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.