A summary of the implementation principle of the C + + compiler for polymorphism

Source: Internet
Author: User

Problem: Define an empty type, which does not have any member variables or member functions, and does a sizeof operation on this type, the result is?

The result is 1, because an instance of an empty type does not contain any information, and the result is 0 after the reason that sizeof evaluates, but when declaring any type of instance, the memory must occupy a certain amount of space, otherwise the instances cannot be used, and the compiler determines how much memory is occupied.

Continue to ask: if you add a constructor and destructor to this type, what is the result?

Or 1, because we call constructors and destructors, only need to know the address of the function, and the address of these functions is only related to the type, and the type of the instance independent, the compiler does not add any additional information to the two functions in the instance.

Continue to ask: if the destructor becomes a virtual function? How much is the result?

The C + + compiler found a virtual function in the type, and a virtual function table is generated for the type, and a pointer to the virtual function table is added to each instance of the type, in a 32-bit machine, the pointer type size is 4 bytes, the result is 4, the 64-bit machine, the pointer size is 8 bytes, the result is 8.

The implementation effect of object-oriented polymorphism

Polymorphic: The same invocation statement has many different forms of expression

Look at the following code example:

classanimal{ Public:    voidsleep () {cout<<"Animal Sleep"<<Endl; }    voidBreathe () {cout<<"Animal Breathe"<<Endl; }};classFish Publicanimal{ Public:    voidBreathe () {cout<<"Fish Bubble"<<Endl; }};intMainvoid) {fish fh; Animal*pan=&FH; PAn-Breathe (); return 0;} 

The parent class pointer points to the subclass object, calls the Breathe method, and the result is animal breathe, which means that the breathe method of the parent class is called. This does not achieve polymorphism. Because the C + + compiler is compiling, to determine the address of the function called by each object, which is called early binding (early binding), when the address of the object FH of the fish class is assigned to the pan pointer of the parent class, the C + + compiler makes a type conversion, It holds that the pointer variable pan of the parent class holds the address of the animal object. When you execute Pan->breathe () in the main () function, the breathe function of the animal object is called.

Further said:

When we construct the object of the fish class, we first call the parent class: the constructor of the animal class to construct the object of the animal class, and then call the fish class's constructor to complete the construction of its own part, thus stitching up a complete fish object. When an object of the fish class is converted to a animal type, the object is considered the upper half of the entire memory model of the original object, which is the "Memory of the Animal object" in the figure.

It is, of course, the method in memory that invokes a type-converted object Pointer to invoke its method. Therefore, the output animal breathe. This is not a polymorphic form of expression.

Three conditions for polymorphic implementations

The prerequisite is that there must be an inheritance relationship, and then we need the parent pointer (reference) to invoke the object of the subclass, and the key is that the subclass has an override of the virtual function of the parent class. The virtual keyword tells the compiler that this function supports polymorphism, and we don't judge how to invoke a method based on the pointer type, but rather the actual object type that the pointer points to.

The theoretical basis of polymorphism

In the previous example, the result of the output is that the compiler has already determined the address of the function called by the object at compile time, and it is necessary to use the late binding (late binding) technique to solve this problem. When the compiler uses late binding, it then determines the type of object and the correct calling function at run time. For the compiler to use late binding, the virtual keyword is used when declaring a function in a base class, which we call a virtual function. Once a function is declared as virtual in the base class, the function is virtual in all derived classes and does not need to be explicitly declared as virtual.

Called dynamic linking: the invocation of an overriding function is judged by the actual object type.

The implementation principle of polymorphism in C + +

When a virtual function is declared in a class, the compiler generates a virtual function table in the class, the virtual function table is a data structure that stores the class member function pointers, the virtual function table is automatically generated and maintained by the compiler, and the virtual member function is put into the virtual function table by the compiler, and when there is a virtual function, Each object has a pointer to a virtual function table (vptr pointer)

, the compiler provides a virtual table pointer to the object for each class vptr, which points to the virtual function table of the class to which the object belongs. When the program is running, initialize the vptr according to the type of the object, so that vptr correctly points to the virtual table of the owning class, so that when the virtual function is called, the correct function can be found.



In the example above:

    fish fh;     *pan=&fh;    PAn->breathe ();

Because the pointer to the parent class is the object type that the pan actually points to, so vptr points to the vtable of the subclass fish class, and when Pan->breathe () is called, the Breathe () function of the fish class is found based on the address of the function in the virtual table. It is because the virtual function that each object calls is indexed by the virtual table pointer, it is very important to determine the correct initialization of the virtual table pointer. In other words, we are not able to invoke virtual functions until the virtual table pointers are properly initialized.

So when, or where, is the virtual table pointer initialized?
C + + is the creation of virtual tables in constructors and the initialization of virtual table pointers.

constructor invocation Order: When constructing a subclass object, the constructor of the parent class is called first, at which point the compiler only "sees" the parent class and does not know if there is a successor later, it initializes the virtual table pointer vptr of the parent class object, which points to the virtual table of the parent class. When the constructor of a subclass is executed, the virtual table pointer vptr of the subclass object is initialized, at which point vptr points to its own virtual table. When the FH object of fish class is constructed, the virtual table pointer inside it is initialized to a virtual table pointing to the fish class.

After the type conversion, call Pan->breathe (), since the pan actually points to the object of the fish class, the virtual table pointer inside the object points to the virtual table of the fish class, so the final call is the Breathe () function of the fish class.

Description

Calling an overriding function through the virtual function table pointer vptr is done when the program runs, so you need to address it to determine which function is really supposed to be called. The normal member function is a function that determines the call at compile time. In efficiency, the efficiency of virtual function is much lower. For efficiency reasons, it is not necessary to declare all member functions as virtual functions

When an object is created, it is initialized by the compiler to the vptr pointer, and only when the object's construction is completely finished vptr the pointer is finally determined, whether the parent object's vptr points to the parent virtual function table or the child class object's vptr point to the subclass virtual function table.

Back to the beginning of the question:

class a{    void  g () {...}}; Then sizeof (A)=1; If you change to the following:class  a{public:      Virtualvoid  f ()    {       ...    }     void g () {...}}

sizeof (A) = 4, because virtual function exists in class A, in order to implement polymorphism, each class containing virtual function implicitly contains a static virtual pointer vptr to the static virtual table vtable of the class. The table entry in vtable points to the entry address of each virtual function in the class.

Polymorphism is the implementation of dynamic binding in a program, rather than a static binding that determines the calling method of an object at compile time.

When the program runs to dynamic binding, it can be polymorphic by vptr the object type pointed to by the pointer of the base class, by locating the vtable it points to, and then calling its corresponding method. This is dynamic binding, or late-compile (lazy).

class Base;Base*pbase;class Base{ Public:    Base() {pbase= This; }    Virtual voidfn () {cout<<"Base"<<Endl; }};classDerived Public Base{    voidfn () {cout<<"derived"<<Endl; }};d erived AA;intMainvoid) {pbase-fn (); return 0;}

In the constructor of the base class, save the this pointer to the PBASE global variable. When you define a global object AA, which calls derived AA, the constructor of the base class is called, the part of the base class is first constructed, and then the part of the subclass, and the complete object AA is stitched up by the two parts.

The this pointer is of course a AA object, so we use PBase in the main () function to call FN (), because PBase actually points to a AA object, and the virtual table pointer inside the AA object points to its own virtual table, which is, of course, the FN in the derived class ( function

When you declare the FN () function in the derived class, you forget to add the public keyword, which causes the declaration to be private (the default is private), but through the virtual function call mechanism we described earlier, we understand that this place does not affect the output of the correct result. Do not know that this is not a C + + bug, because the call of the virtual function to determine which function to call at run time, so the compiler at compile time, do not know that pbase point to a AA object, so the occurrence of this strange phenomenon. If you call directly with a AA object, because the object type is deterministic (note that AA is an object variable, not a pointer variable), the compiler tends to use early binding to determine the function that is called at compile time, so you will find that FN () is private and cannot be called directly.

What happens if a virtual function is called directly in the constructor of the base class?

When calling the constructor of a base class, the compiler only "sees" the parent class and does not know if there are successors later, it simply initializes the virtual table pointer of the parent class object, and the virtual table pointer points to the virtual table of the parent class, so the result is certainly incorrect. Only after the constructor call of the subclass is complete, the entire virtual table is built, so that C + + polymorphism can be truly applied. In other words, do not invoke the virtual function in the constructor to implement polymorphism, of course, if you just want to invoke the function of this class, it doesn't matter.

Get a conclusion:

The constructor calls the Polymorphic function and cannot implement polymorphism.

Comparison of virtual function and pure virtual function

Virtual functions

Introduction Reason: In order to facilitate the use of polymorphic properties, we often need to define virtual functions in the base class.

Pure virtual function

Introduction Reason: In order to achieve polymorphism, pure virtual function is a bit like the interface in Java, not to implement the process, let inherit his sub-class to achieve. In many cases, the base class itself generates objects that are unreasonable. For example, animals as a base class can be derived from tigers, peacocks and other sub-categories, but the animals themselves generated objects are obviously unreasonable. At this point we will define the animal class as abstract class, that is, the class containing pure virtual function, pure virtual function is the base class only defines the function body, there is no implementation process:

Virtual void 0; Direct =0

The difference between virtual function and pure virtual function
The function in the virtual function is the implementation of even an empty implementation, its role is that the function in the subclass can be overloaded, runtime dynamic binding implementation of dynamic, and pure virtual function is an interface, is a function declaration, is not implemented in the base class, to wait until the subclass to implement
Virtual functions can not be overloaded in subclasses, but virtual functions must be implemented in subclasses.

Summarize:

For virtual function calls, there is a virtual table pointer inside each object that is initialized to the virtual table of this class. So in a program, no matter how your object type is converted, but the virtual table pointer inside the object is fixed, it is possible to implement dynamic object function calls, which is the principle of C + + polymorphism implementation.

If the base class has virtual functions:

1, each class has a virtual table.

2, the virtual table can inherit, if the subclass does not override the virtual function, then the sub-class virtual table will still have the address of the function, but this address refers to the virtual function of the base class implementation. If the base class is 3 virtual functions, then there are three items in the virtual table of the base class (virtual function address), the derived class also has a virtual table, at least three items, if the corresponding virtual function is overridden, then the address in the virtual table will change, pointing to its own virtual function implementation. If a derived class has its own virtual function, the item is added in the virtual table.

3. The order of the virtual function address in the virtual table of the derived class is the same as the virtual function address in the virtual table of the base class.

A summary of the implementation principle of the C + + compiler for polymorphism

Related Article

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.