C + + multi-state implementation and vritual principle

Source: Internet
Author: User

http://blog.csdn.net/zyq0335/article/details/7657465

1 What is polymorphism?
Polymorphism can be simply summed up as "1 interfaces, multiple methods", in the process of running the program to determine the mechanism of the call
On the implementation of the program, you can make the parent pointer have multiple forms by calling the function of the child class through the parent pointer.
2 Implementation Mechanism
To give an example:
#include <iostream.h>
Class Animal
{
Public
void Sleep ()
{
cout<< "Animal Sleep" <<endl;
}
void Breathe ()
{
cout<< "Animal Breathe" <<endl;
}
};
Class Fish:public Animal
{
Public
void Breathe ()
{
cout<< "Fish Bubble" <<endl;
}
};
void Main ()
{
Fish FH;
Animal *pan=&fh;
Pan->breathe ();
}
The answer is output: animal breathe
Results Analysis:
1 from the point of compilation
When compiling the C + + compiler, to determine the address of the function called by each object, which is called early binding (early binding), when we assign the address of the fish class object FH to the pan, the C + + compiler makes a type conversion, at which time C + + The compiler thinks that the variable pan holds the address of the animal object. When executing pan->breathe () in the main () function, the call is of course the breathe function of the animal object.
2 The angle of the memory model
When we construct the fish class object, we first call 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 we convert an object of fish class to a animal type, the object is considered the upper half of the entire memory model of the original object, which is the "memory occupied by the animal object" in Figure 1-1. So when we use a type-converted object Pointer to invoke its method, it is, of course, the method in memory where it is called. Therefore, the output animal breathe, it is logical.

To get the results we want, we're going to use virtual functions.

The result of the preceding 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. In order for the compiler to use late binding, the virtual keyword is used when declaring a function in a base class (note that this is necessary, and many students simply write many examples of errors without using virtual functions), which we call virtual functions.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.

Let's make some changes to the code above

virtual void Breathe ()
{
cout<< "Animal Breathe" <<endl;
}
Running Result: Fish bubble
Results analysis
The compiler provides a virtual table pointer to the object of each class that points to the virtual 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.

Since the object type that the pan is actually pointing to is fish, so the vtable of the fish class that vptr points to, 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?
The answer is to create the virtual table in the constructor and initialize the virtual table pointer. Remember the order in which constructors are called, when constructing a subclass object, the constructor of the parent class is called, at which point the compiler only "sees" the parent class, does not know if there are successors after it, initializes the virtual table pointer of the parent class object, and the virtual table pointer points to the virtual table of the parent class. When the constructor of a subclass is executed, the virtual table pointer of the subclass object is initialized, pointing 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.

To explain the memory distribution more clearly: The following details describe the distribution of memory

1 The memory distribution of the base class

take a look at the sample below
class A
{
void G () {...}
};
then sizeof (A) =1;
If you change to the following:
class A
{
Public :
virtual void f ()
    {
       ......
    }
void G () {...}
}
then sizeof (A) =4! This is because virtual function exists in class A, in order to implement polymorphism, each class containing virtual function implicitly contains a static virtual pointer vfptr 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
For example, we declare an object of type a:
A C;
A D;
The memory distribution after compilation is as follows:



As you can see from the vtable pointed to by vfptr, each virtual function occupies a entry, such as the F function in this example. The G function is not in the vtable table entry because it is not a virtual type. Description: Vtab belongs to class member static pointer, while vfptr belongs to object pointer
2 Memory distribution of inherited classes
Suppose the code is as follows:
Public b:public A
{
Public :
int f ()//override virtual function
    {
return 3;
    }
};
the
A C;
A D;
B E;
after compiling, its memory is distributed as follows:

as we can see, object E of type B has a vfptr point to vtable address:0x00400030, while objects C and D of type a collectively point to the vtable of the class address:0x00400050a
3 Implementation of dynamic binding process
we say that polymorphism is achieved by dynamic binding in the program, rather than at compile time to determine the static binding of the object's calling method.
the process is as follows:
When the program runs to dynamic binding, it can be polymorphic by vfptr 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.
For example:
A C;
B E;
A *pc=&e;//Set breakpoint, run here
pc=&c;
at this point in memory the pointer status is as follows:


As you can see, the PC points to the virtual table address of Class B and calls the method of object E.

Continue to run, when running to Pc=&c, at this time the vptr value of the PC is 0x00420050, that is, point to the vtable address of Class A, thus calling the method of C.
This is dynamic binding! (dynamic binding) or late-compile (lazy).


Summary:
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.
Some summaries to note (base classes have virtual functions):
1, each class has a virtual table, the subclass of a single inheritance has a virtual table, the subclass object has a virtual table pointer, if the subclass is multiple inheritance (while inheriting multiple base classes ), the subclass maintains multiple virtual function tables (for different base classes to build different virtual tables), the object of the subclass will also contain Multiple virtual table pointers .

About the memory layout of multiple Inheritance Reference blog:http://blog.chinaunix.net/uid-16723279-id-3568748.html

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.


2 A good example (this pointer is pointing to a subclass)
#include <iostream.h>

Class Base;

Base * pbase;

Class Base
{
Public
Base ()
{
Pbase=this;

}
virtual void fn ()
{
cout<< "Base" <<endl;
}
};

Class Derived:public Base
{
VOID Fn ()
{
cout<< "Derived" <<endl;
}
};

Derived AA;
void Main ()
{
PBASE-&GT;FN ();
}

I saved the this pointer to the PBASE global variable in the constructor of the base class. 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., we use PBase to call FN () in the main () function, 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 () function in the derived class.

In this case, because of my negligence, when declaring the FN () function in the derived class, I forgot to add the public keyword, causing the declaration to be private (the default is private), but through the virtual function call mechanism we described earlier, We also understand that this place does not affect the output of the correct results. 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, and then it finds that FN () is private and cannot be called directly. :)

Many students write this example, directly in the constructor of the base class call virtual function, as previously said, when calling the base class constructor, the compiler only "see" The parent class, do not know if there is a successor after, it just initializes the parent object of the virtual table pointer, so that the virtual table pointer to the virtual table of the parent class, So you see the result is certainly not correct. 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, let's not call the virtual function in the constructor, but it doesn't matter if you just want to invoke the function of this class.

When we talk about virtual function, we should compare virtual function with 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 define the animal class as an abstract class, that is, a class containing pure virtual functions.
Pure virtual function is the base class only defines the function body, there is no implementation process definition method as follows

virtual void Eat () = 0; Direct =0 don't define it in CPP.
The difference between virtual function and pure virtual function
1 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, run-time dynamic binding implementation of dynamic
Pure virtual function is an interface, is a function declaration, in the base class is not implemented, to wait until the subclass to implement
2 virtual functions can not be overloaded in subclasses, but pure virtual functions must be implemented in subclasses.

C + + multi-state implementation and vritual principle

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.