On the realization principle of virtual function in C + + the revelation _c language

Source: Internet
Author: User

What exactly did the compiler do to implement the late binding of virtual functions? Let's find out what's going on.

The compiler creates a table (called V TA B L E) for each class that contains a virtual function. In v TA B L E, the compiler places the virtual function address of a particular class. In each class with a virtual function, the compiler secretly put a pointer, called V P o i n T e R (abbreviated to V P t r), pointing to the V TA B L E of this object. When a virtual function call is made through a base class pointer (that is, a long state call), the compiler statically inserts the code that obtains the V P T R and looks for the address of the function in the V TA B L e table, so that the correct function can be invoked to make the late bundle happen. Set v TA B L E, initialize v P R, and insert code for virtual function calls for each class, so we don't have to worry about that. With a virtual function, the appropriate function of this object can be invoked even if the compiler does not know the specific type of the object. ("C + + programming Ideas")

There is no type information displayed in any class, but class information must be stored in the object, or the type cannot be built at run time. So what is this kind of information?

Let's look at a few of 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;

Of the above three classes:

No_virtual has no virtual function, sizeof (no_virtual) = 4,

The length of a class no_virtual is the length of the integral type A of its member variable;

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 and the length of a void pointer, which reflects that if there is one or more virtual functions, the compiler inserts a pointer into the structure (V P T R). There is no difference between one_virtual and two_virtual. This is because V P r points to a table that holds an address, and only one pointer is required because all virtual function addresses are contained in this table. This vptr can be regarded as the type information of the class.

So let's take a look at how the compiler created the virtual function table that vptr pointed to. First 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) pointed to by the two class vptr 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 the previous illustration. 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 that is 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 the vtable of derived, Vfun2 's entrance is the case.) The compiler then places the vptr in this class. When using simple inheritance, there is only one vptr for each object. 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 only useful when the virtual function is invoked.

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 the class. Each of its table entries is the virtual function address of the class.

2, when defining the derived class object, the constructor of its base class is called First, then the vptr is initialized, and finally the constructor of the derived class is called (from the binary perspective, the so-called base class subclass is a large structure in which the four bytes at the beginning of the this pointer holds the virtual function header pointer.) When the constructor of a subclass is executed, the base class constructor is called first, the this pointer as a parameter, the vptr of the base class in the base class constructor, and then back to the constructor of the subclass, filling in the vptr of the subclass, overwriting the vptr that the base class fills in. Thus completes the initialization of the vptr. )

3, in the implementation of dynamic binding time, can not directly adopt class objects, but must use pointers or references. Because of the way in which class objects are passed, a temporary base class object is generated, and a pointer is used to access the vptr of the external derived class object through the pointer 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 VPTR value to determine the location of the vtable. Vptr always points to the start address of the vtable, and the virtual function address of all base classes and its subclasses (except for the virtual functions defined by the subclass itself) is always stored in the same location in vtable, as in vtable and vfun1 of the base class and derived class above. Addresses are always stored in the same order. The compiler knows that VFUN1 is at VPTR and Vfun2 is at vptr+1, so when calling a virtual function with a base class pointer, the compiler gets the pointer to the object's type information (VPTR) first, and then calls the virtual function. If a base class pointer pbase to a derived object, that pbase->vfun2 () is translated by the compiler into a vptr+1 call, because the address of the virtual function vfun2 is located in the vtable at index 1. Similarly, pbase->vfun3 () is translated by the compiler as a vptr+2 call. This is called late binding.

This article discusses the virtual function in C + + the realization of the principle of the secret is small to share all the content of everyone, hope to give you a reference, but also hope that we support the cloud habitat community.

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.