C + + Object-oriented language A major difficulty is inheritance, but it has to be mastered. Simple inheritance is easy to understand, but when it comes to multiple inheritance, design to virtual function inheritance, especially when it comes to virtual inheritance, the problem becomes complex. The following is from three articles in the Resources section. In the inheritance learning of C + +, the most important thing is to master the object model of the derived class , the upward-downward type conversion between the base class and the derived class pointers , and when the virtual function member function accesses (polymorphic) in the inheritance, how virtual inheritance is solved by introducing the virtual base table to "Diamond inheritance "There are several common base classes in the problem.
A Simple object model
1. Definition
class MyClass { public : int var ; void foo () {} // normal member function virtual void Fun () {} // virtual member function };
the MyClass object size is 8 bytes. The first four bytes store the pointer vfptr of the virtual function table , and the second four bytes store the value of the object member Var. The size of the virtual function table is 4 bytes, the address of a function, that is, the address of the virtual function fun , which is the offset of the virtual function table vftable is 0. Therefore, theresults of the MyClass object model are shown ( in a 64-bit machine, the size of the pointer is 8 bytes.) So the MyClass object size is supposed to be three bytes. The first 8 bytes store the virtual function table pointer vfptr, the last four bytes store the value of the object member Var, plus the memory alignment is 16 bytes)
MyClass's virtual function table has only one function record, but it ends with 4 bytes of 0 as the closing tag.
Adjust represents the adjustment of this pointer when the virtual function mechanism executes, if the fun is called by polymorphic, then it is in the following form:
* (this+0) [0] ()
Summarize the virtual function call form, should be:
* (this pointer + adjust amount) [virtual function offset within vftable] ()
Second, single inheritance
Defines the derived class Myclassa, inherits from the MyClass class, Overrides Foo (), Fun (), and defines Funa ().
In the form of single inheritance, the subclass's virtual function table and data are fully obtained by the parent class. Subclasses if the virtual function of the parent class is overridden (such as fun), the record (content Myclass::fun) corresponding to the original fun of the virtual function table is overwritten with the new function address (content Myclassa::fun), otherwise the original function address record is persisted. If a subclass defines a new virtual function, a record is appended to the virtual function table that records the address of the function (such as Myclassa::funa). Its object model such as
class Public MyClass {public: int VarA; void foo () { } virtualvoid Fun () { } virtual void Funa () { }};
The up-down type conversions under non-virtual inheritance are easy and complete with static transformations. When a derived class overrides a method of a base class, access to the normal member function depends on the type of pointer, and the virtual function's access depends on what the pointer points to. For non-virtual member functions, which member function is called is statically determined at compile time according to the type of the left pointer expression of the "-a" operator. For virtual function calls, which member function to invoke is determined at run time. The virtual function that is called is determined by the instance type that the pointer actually points to, regardless of the type of the pointer expression to the left of the "-a" operator. (This is polymorphism in C + +). In order to implement this mechanism, a hidden VFPTR member variable is introduced. A vfptr is added to the class (if not in the class), and the vfptr points to the virtual function table (vftable) of the class. Each virtual function in a class occupies an item in the Virtual function table of the class. Each item holds an address for the virtual function that the class applies to. Therefore, the process of calling the virtual function is as follows: Obtain the vfptr of the instance, get an item of the virtual function table by Vfptr, and call the virtual function indirectly through the function address of the item in the Virtual function table. In other words, the virtual function call requires additional overhead in addition to the argument passing, calling, and return instruction overhead of the normal function call.
For example, in the following example:
- The call of the normal member function foo () function, regardless of the object's content, Derivaed->foo () always calls the Foo function in the derived class, and Base->foo () always calls the Foo function in the base class.
- A virtual function call depends on the type of object that the pointer points to, such as the first Base->fun (), because base points to a derived object and calls the fun () method in the derived class. Deriveda->fun () in a homogeneous down conversion is called the Fun () function in the base class.
//convert upmyclassa* deriveda=NewMyclassa (); MyClass*Base= static_cast<myclass*>(Deriveda); Deriveda->foo ();//Myclassa:foo ()Deriveda->fun ();//Myclassa:fun () Base->foo ();//Myclass:foo () Base->fun ();//myclassa:fun () polymorphic//Down ConversionBase=NewMyClass (); Deriveda= Static_cast<myclassa*> (Base); Base->foo ();//Myclass:foo () Base->fun ();//Myclass:fun ()Deriveda->foo ();//Myclassa:foo ()Deriveda->fun ();//myclass:fun ()
Three, multiple inheritance
In order to introduce, the definition of MYCLASSB,MYCLASSB and Myclassa similar, do not repeat. It also defines a MYCLASSC that inherits from Myclassa and MYCLASSB at the same time.
classMYCLASSB: PublicMyClass { Public: intVarb; voidfoo () {}Virtual voidFun () {}Virtual voidFunb () {}};classMYCLASSC: PublicMyclassa, Publicmyclassb{ Public: intVarc; voidfoo () {}Virtual voidFunb () {}Virtual voidFUNCC () {}};
Similar to single-inheritance, when multiple inheritance is MYCLASSC, all of the parent classes are included in their own order, and each parent class corresponds to a separate virtual function table.
Under multiple inheritance, a subclass no longer has its own virtual function table, and its virtual function table is merged with the virtual function table of the first parent class. Similarly, if a subclass overrides a virtual function of any parent class, the corresponding function address record is overwritten. If MYCLASSC overrides the Fun function (two parent classes have this function), then the records of the two virtual function tables need to be overwritten! Here we find that the MYCLASSC::FUNB function corresponds to the Adjust value is 12, according to our preceding rule, we can find that the function of the polymorphic invocation form is:
* (THIS+12) [1] ()
The amount of adjustment here is 12 exactly the offset of the MYCLASSB vfptr within the MYCLASSC object. (32-bit machine)
As with multiple inheritance and single inheritance, you can use static transformations to accomplish down-type conversions, but the addresses of pointers are different when you convert to different types.
New MYCLASSC (); Myclassa* da = static_cast<myclassa*>(DDC); MYCLASSB* db = static_cast<myclassb*>(DDC); << DDC << Endl; // 0x11a7c20 cout << da << endl; // 0x11a7c20, the first inheriting class Myclassa cout << db << Endl; // 0X11A7C30, second inheriting class MYCLASSB
In addition, in this multi-inheritance relationship, two inheriting classes Myclassa and MYCLASSB inherit the class MyClass class, which is also known as the "Diamond" inheritance.
The attentive reader will find that there are multiple copies of the derived class, members of the public base class, and VAR member variables in this sample.
In a diamond-like inheritance relationship, it is not possible to go directly up to the public base class, or to access the members of the public base class directly, because the compiler appears to be ambiguous behavior, and the compiler will error if it comes from Myclassa or MYCLASSB.
base = static_cast<myclass*>(DDC); << ddc->var << Endl;
error: ' MyClass ' is an ambiguous base of ' myclassc '
Error:request for member ' var ' is ambiguous
The right approach is to indicate which inheritance class to avoid ambiguity
Base = static_cast<myclass*> (static_cast<myclassa*>(DDC)); << Ddc->myclassa::var << Endl;
Iv. Virtual Inheritance
In C + +, in order to avoid diamond inheritance, the derivation class has a multi-fee common base class copy problem, introduced the concept of virtual inheritance.
Virtual base table pointers are introduced in virtual inheritance, which makes the inheritance problem more complicated. Although in single inheritance, virtual inheritance is generally not present, but in order to understand the virtual inheritance in step-by-step, or from the virtual inheritance of single inheritance start.
The use of virtual inheritance is very simple, just need to precede ordinary inheritance with the virtual keyword can be, for example, Myclassa virtual inherit from the MyClass class:
class Myclassa: virtual public MyClass {public: int VarA; void foo () { } virtualvoid Fun () { } virtual void Funa () { }};
The memory layout of the Myclassa object, the size of the Myclassa class is 40 bytes under the VS64 bit platform, and the GCC64 bit platform is 32 bytes. These two implementations on virtual inheritance may be somewhat different, where the VS compiler introduces the model of the Myclassa object to the class. The following is the use of vs2012 to see the Myclassa
Class Myclassa Size (40):
1> +---
1> 0| {VFPTR}
1> 8| {VBPTR}
1> 16| VarA
1> | <alignment member> (size=4)
1> +---
1> +---(virtual base MyClass)
1> 24| {VFPTR}
1> 32| Var
1> | <alignment member> (size=4)
1> +---
1>
1> Myclassa::[email protected]@:
1> | &myclassa_meta
1> | 0
1> 0| &myclassa::funa
1>
1> Myclassa::[email protected]:
1> 0| -8
1> 1| (Myclassad (myclassa+8) MyClass)
1>
1> Myclassa::[email protected]@:
1> | -24
1> 0| &myclassa::fun
1>
1> Myclassa::fun This adjustor:24
1> Myclassa::funa This adjustor:0
Converted to a graph, as shown in Vbtable, 8 represents the difference between the first vfptr and the Vbptr, and 16 represents the difference between the second vfptr and the vbptr.
The biggest implication of our virtual inheritance is that "diamond inheritance" avoids the content of multiple copies of respect in a derived class. Homogeneous redefinition myclassb virtual inheritance from Myclass,myclassa inherit from Myclassa and MYCLASSB.
MYCLASSB memory structure and MYCLASSA memory structure similar, no longer repeat. The main analysis of MYCLASSC memory structure.
classMYCLASSB:Virtual PublicMyClass { Public: intVarb; voidfoo () {}Virtual voidFun () {}Virtual voidFunb () {}};classMYCLASSC: PublicMyclassa, Publicmyclassb{ Public: intVarc; voidfoo () {}Virtual voidFunb () {}Virtual voidFunC () {}
virtual void Fun () {}};
1> class MYCLASSC Size (72):
1> +---
1> | +---(base class Myclassa)
1> 0| | {VFPTR}
1> 8| | {VBPTR}
1> 16| | VarA
1> | | <alignment member> (size=4)
1> | +---
1> | +---(base class MYCLASSB)
1> 24| | {VFPTR}
1> 32| | {VBPTR}
1> 40| | Varb
1> | | <alignment member> (size=4)
1> | +---
1> 48| Varc
1> | <alignment member> (size=4)
1> +---
1> +---(virtual base MyClass)
1> 56| {VFPTR}
1> 64| Var
1> | <alignment member> (size=4)
1> +---
1>
1> Myclassc::[email protected]@:
1> | &myclassc_meta
1> | 0
1> 0| &myclassa::funa
1> 1| &myclassc::func
1>
1> Myclassc::[email protected]@:
1> | -24
1> 0| &myclassc::funb
1>
1> Myclassc::[email protected]@:
1> 0| -8
1> 1| (MYCLASSCD (myclassa+8) MyClass)
1>
1> Myclassc::[email protected]@:
1> 0| -8
1> 1| (MYCLASSCD (myclassb+8) MyClass)
1>
1> Myclassc::[email protected]@:
1> | -56
1> 0| &myclassc::fun
1>
1> Myclassc::funb This adjustor:24
1> Myclassc::func This adjustor:0
1> Myclassc::fun This adjustor:56
Note the MYCLASSC object model, which shows the contents of the virtual inheritance class from top to bottom, first myclassa the contents according to the inheritance order, then the contents of the MYCLASSB, and finally the contents of the public base class, with the exception that each virtual inheriting class has a virtual base table pointer.
Access to virtual public base class members in dummy inheritance:
Virtual inheritance can avoid ambiguity in the access of common base class members in Diamond inheritance. We know that in non-inheritance, single-inheritance, and even multiple-inheritance relationships, access to members is done by offsets between the multi-base class pointer and the base class member. In virtual inheritance, the member accessing the virtual base class is still calculating a fixed offset, but accessing the members of the public virtual base class becomes very expensive and requires access to the contents of two virtual pointers, in the following steps:
New MYCLASSC (); << vddc->var << Endl;
1. Get a virtual base table pointer, here is the first VBTR
2. Get the contents of an item in a virtual base table, this is 40
3. Add the offset indicated in the content to the address of the "Virtual base class table pointer" to access the contents of the public virtual base class.
Up-down type conversions in virtual inheritance:
1. Virtual inheritance in the same way as the general inheritance, using static_cast static conversion
New MYCLASSC (); Myclassa* Vda = static_cast<myclassa*> (VDDC);
2. The public virtual base class down conversion in virtual inheritance is not allowed to use static conversions because of the need for runtime information.
New MyClass (); MYCLASSC* VDDC = static_cast<myclassc*> (VD);
Error:cannot convert from pointer to base class ' MyClass ' to pointer to derived class ' MYCLASSC ' because the base is Virt ual
Need to use dynamic conversion, dynamic_cast
New MyClass (); MYCLASSC* VDDC = dynamic_cast<myclassc*> (VD);
Through the above description, we basically recognize the C + + object model. Especially in the complex structure under the multiple and virtual inheritance. Through these real examples, we are able to understand the nature of class in C + + in order to guide us to better write our program. This article is based on the object structure of the legend for everyone to explain the basic model of the object, and general description of C + + virtual mechanism of the article is different. The author only hope that the use of the chart can put C + + objects in a better understanding of the form for everyone to show, I hope this article is helpful to you.
Resources:
1.http://www.cnblogs.com/fanzhidongyzby/archive/2013/01/14/2859064.html
2.http://www.oschina.net/translate/cpp-virtual-inheritance
3.http://www.cnblogs.com/cy568searchx/p/3707384.html
C + + inheritance, multiple inheritance, virtual inheritance object model