The realization principle of virtual function in C + +

Source: Internet
Author: User

What exactly did the compiler do to implement the late binding of the virtual function?      Let's find out. The compiler creates a table for each class that contains virtual functions (called V TA B L E). In v TA B L E, the compiler places a virtual function address for a particular class. In each class with virtual functions, the compiler secretly place a pointer, called V P o i n T e R (abbreviated to V P t r), pointing to the object's V TA B L E. When a virtual function call is made by a base-class pointer (that is, when a long call is made), the compiler statically inserts the code that obtains the V P T R and finds the function address in the V TA B L e table, so that the correct function can be called to make the late bundle happen. Set v TA B L E for each class, initialize v P T R, insert code for virtual function calls, all of which happen automatically, so we don't have to worry about that. With virtual functions, the appropriate function of this object can be called, even if the compiler does not yet know the specific type of the object. ("C + + programming Idea")
There is no type information displayed in any class, and the class information must be stored in the object, otherwise the type cannot be established at run time. What about this kind of information? Let's look at the following classes: Class No_virtual
{
Public
void Fun1 () const{}
int fun2 () const {return A;}
Private
int A;
} class One_virtual
{
Public
virtual void fun1 () const{}
int fun2 () const {return A;}
Private
int A;
} class Two_virtual
{
Public
virtual void fun1 () const{}
virtual int fun2 () const {return A;}
Private
int A;
} The above three classes:
No_virtual has no virtual function, sizeof (no_virtual) = 4, the length of class no_virtual is the length of its member variable integral type A;
One_virtual has a virtual function, sizeof (one_virtual) = 8;
Two_virtual has two virtual functions, sizeof (two_virtual) = 8, there is no difference in the length of a class with a virtual function and two virtual functions, in fact their length is the length of the no_virtual plus the length of a void pointer, which reflects If there is one or more virtual functions, the compiler inserts a pointer (V P T R) into the structure. There is no difference between one_virtual and two_virtual. This is because V P T r points to a table that holds the address, and only requires a pointer, because all virtual function addresses are included in the table.        This vptr can be regarded as the type information of the class. So let's see how the compiler built this virtual function table that vptr points to. Let's look at the following two classes:
Class Base
{
Public
void Bfun () {}
virtual void Vfun1 () {}
virtual int vfun2 () {}
Private
int A;
} class Derived:public Base
{
Public
void Dfun () {}
virtual void Vfun1 () {}
virtual int vfun3 () {}
Private
int b;
The Virtual function table (VTABLE) that the two class vptr points to is as follows:
Base class
——————
Vptr--> |&base::vfun1 |
——————
|&base::vfun2 |
——————

Derived class
———————
Vptr--> |&derived::vfun1 |
———————
|&base::vfun2 |
———————
|&derived::vfun3 |
———————

Whenever you create a class that contains a virtual function or derive a class from a class that contains a virtual function, the compiler creates a vtable for the class, as shown in. In this table, the compiler places the address of all functions declared as virtual in this class or in its base class. If a function declared as virtual in the base class is not redefined in this derived class, the compiler uses this virtual function address of the base class. (in Derived's vtable, Vfun2 's entrance is the case.) The compiler then places vptr in this class. When simple inheritance is used, there is only one vptr for each object. The vptr must be initialized to point to the corresponding vtable, which occurs in the constructor.
Once vptr is initialized to point to the corresponding vtable, the object "knows" what type it is. But this self-awareness is useful only when the virtual function is called.The personal summary is as follows:
1. When deriving a class from a class that contains a virtual function, the compiler creates a vtable for that class. Each of its table entries is the virtual function address of the class.
2. When defining the derived class object, call the constructor of its base class first, then initialize the vptr, and finally call the constructor of the derived class (from the binary perspective, the so-called base class subclass is a large struct, where the four bytes at the beginning of the this pointer hold the virtual function header pointer.) When executing the constructor of a subclass, first call the base class constructor, the this pointer as an argument, fill in the base class constructor with the vptr of the base class, and then go back to the constructor of the subclass, fill in the vptr of the subclass, overwrite the vptr that the base class fills in. This completes the initialization of the vptr. )
3, in the implementation of dynamic binding, can not directly adopt the class object, but must adopt a pointer or reference.        Because of the way in which class objects are passed, there are temporary base class objects, and pointers are used to access the external vptr of derived class objects to achieve the result of accessing the derived class virtual function. VPTR is often at the beginning of an object, and the compiler can easily take the value of VPTR to determine the location of the vtable. Vptr always points to the start address of the vtable, and the virtual function addresses of all base classes and its subclasses (except for the subclass's own defined virtual functions) are always stored in the same location in vtable, such as vtable and vfun1 in the base class and derived class above vfun2 The addresses are always stored in the same order. The compiler knows that VFUN1 is located at VPTR and Vfun2 is at vptr+1, so when a virtual function is called with a base-class pointer, the compiler first obtains the pointer to the object's type information (VPTR) and then calls the virtual function. such as a base class pointer pbase points to a derived object, that pbase->vfun2 () is translated by the compiler into a call to vptr+1, because the address of the virtual function vfun2 is in vtable at the position of index 1. Similarly, pbase->vfun3 () is translated by the compiler into a vptr+2 call. This is called late binding.

The implementation of virtual functions in C + + secret

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.