Principles of C ++ virtual functions

Source: Internet
Author: User

Understanding virtual functions
Several key points of (virtual function:

1.
Understanding early binding
(Early binding), late binding
(Late binding ). The so-called
Early binding:
On compile time, you can specify the member function of the object to which a function is called, that is, the address of the specific function is known during compilation. The so-called
Late binding:
On compile time, the call to a function (virtual function) is implemented as follows:
Pobj-> _ vptr-> vtable [], resulting in failure
Runtime. The actual function address is unknown. Run the command here until the program runs.
The function address is obtained in the vtable. In fact, the principle is very simple, but if you look at these terms, it will look very simple.
Like magic.

2.
Understand the underlying mechanism on which virtual functions depend:
Vptr + vtable. The implementation of virtual functions is
Vptr/vtbl form, the basis of this technology:

① The Compiler generates a static function pointer array (virtual function table) for each class containing virtual functions in the background ), each virtual function defined in this class or its base class has a corresponding function pointer.

② Each instance of classes containing virtual functions contains an invisible data member
Vptr (virtual function pointer), which is automatically initialized by the constructor and points
Vtbl (virtual function table)

③ When a user calls a virtual function, the compiler generates code pointing back
Vptr, index
In vtbl, find the function pointer at the specified position, and issue a call.

Refer to the reposted Article below:

Virtual functions are declared
Virtual member functions. When the compiler sees that such a function is called through a pointer or reference, it is bound to it later, that is, through a pointer (or reference) the type information of the class to which the function belongs. Generally, such pointers or references are declared as base classes. They can refer to objects of base classes or derived classes.

Polymorphism means that the same method can have different behaviors based on different objects (according to your understanding, I do not know whether it is rigorous to say so ).

The following is an example of virtual functions, polymorphism, early binding, and late binding:

Two siblings (Brother and Sister) of Lee attended the sports meeting with different surnames (team members with different surnames), the men's project competition, and the women's project competition. At the opening ceremony, representatives of participating teams made speeches, both of them want
To show your face, you can only go with one person. In the end, they decided to capture the decision, and the organizing committee did not disagree, so it didn't care whether it was a brother or sister to speak, you only need to send a sentence with the surname Li. Sports Meeting as scheduled
Row, Sister captured the opportunity to speak on behalf of the Li family, Brother participated in the men's project competition, sister participated in the Women's Project Competition. We are not concerned about the results of the competition.

Now let's make an analogy (only discuss topics related to sports meetings ):

(
1) Class Design:

Li's siblings belong to the Li family. Li's is a base class (here it is still an abstract pure base class), and Li's derived two sub-classes (Li's male and Li's female ), all men's projects of the Lee's men's Congress
Number), Lee's female Association All Women's Program competitions (Lee's female member function ). All people surnamed Li will speak (basic functions). Of course, Li's male and Li's female will also speak from Li's, but the voices of men and women are different.
The content is also different, which makes people feel different (Li's male and Li's female respectively redefine the virtual function ). The two siblings are the entities of the male and female.

(
2) Program Design:

Enter the registration form for the contestant.

(
3) Compile:

The registration form of brother and sister li was handed over to the Organizing Committee (compiler). His brother and sister participated in the men's and women's competitions respectively. The Organizing Committee understood at a Glance (early binding ), only the spokesman is unclear. The Organizing Committee will see the report
Which of the following statements is written on the table?
"Li Jia representatives
"(Base class pointer), the organizing committee is not sure who it is, just make a note: If it is male, It is brother Li xx; if it is female, that is, sister li XX (late binding ). Group
After the Commission makes other preparations, it will wait for the sports meeting to begin (compilation is complete ).

(
4) program running:

The sports meeting started (the program started to run). At the opening ceremony, we heard a speech from sister li. If my brother is lucky enough to win, we will hear a speech from his brother (polymorphism ). Then we can see the two sisters in the competition...

I hope this metaphor makes it clear the concept of virtual functions, polymorphism, early binding, and late binding and their relationships. In addition, early binding means that the compiler knows the specific type of the object during compilation and determines the exact address of the member function called by the object; late binding obtains the virtual function table pointer of the Class Based on the type information of the object indicated by the pointer, and then determines the exact address for calling the member function.

2. Uncover late-bound secrets

What is the late binding of virtual functions implemented by the compiler? Let's find out.

The compiler creates a table (called
V ta B L E ). In
In V ta B L E, the compiler places the virtual function address of a specific class. In each class with a virtual function
The compiler secretly sets a pointer, called
V p o I n t e r (abbreviated
V p t r), pointing to the object's
V ta B L E. Implement Virtual function calling through base class pointers

When the compiler is statically inserted to obtain this
V p t r
, And
V ta B L E
Code used to find the function address in the table,
In this way, the correct function can be called to enable later bundling.
Set for each class
V ta B L E, initialization
V p t r, insert code for virtual function calls, all of which happen automatically, so we don't have to worry about this. Using Virtual functions,
The appropriate functions of this object can be called, even if the compiler does not know the specific type of the object. (《

C ++
Programming Ideology
)

----
In this section, the red and bold parts seem a bit problematic. For my personal understanding, refer to the following summary.

No displayed type information exists in any class, and class information must be stored in the object. Otherwise, the type cannot be created at runtime. What is the class information? Let's look at the following classes:

Class no_virtual
{
Public:
Void fun1 () const {}
Int fun2 () const {return ;}
PRIVATE:
Int;
}

Class one_virtual
{
Public:
Virtual void fun1 () const {}
Int fun2 () const {return ;}
PRIVATE:
Int;
}

Class two_virtual
{
Public:
Virtual void fun1 () const {}
Virtual int fun2 () const {return ;}
PRIVATE:
Int;
}

Among the above three categories:

No_virtual has no virtual function,
Sizeof (no_virtual) = 4, Class
The length of no_virtual is the integer type of its member variable.
The length of;

One_virtual has a virtual function,
Sizeof (one_virtual) = 8;

Two_virtual has two virtual functions,
Sizeof (two_virtual) = 8;
There is no difference between the class length of a virtual function and two virtual functions. In fact, their length is
No_virtual
Add one length
Void pointer length, which indicates that if one or more virtual functions exist, the compiler inserts a pointer in this structure (
V p t r ). In
One_virtual and
There is no difference between two_virtual. This is because
V p t r points to a table with a storage address. Only one pointer is required, because all the virtual function addresses are included in this table.

This
Vptr can be seen as the type information of the class.

Let's see how the compiler is built.
Vptr points to the virtual function table. Let's take a look at the following two classes:

Class base
{
Public:
Void bfun (){}
Virtual void vfun1 (){}
Virtual int vfun2 (){}
PRIVATE:
Int;
}

Class derived: public Base
{
Public:
Void dfun (){}
Virtual void vfun1 (){}
Virtual int vfun3 (){}
PRIVATE:
Int B;
}

Two Classes
Virtual function table pointed to by vptr (
Vtable:

Base Class

------
Vptr --> | & base: vfun1 |
------
| & Base: vfun2 |
------

Derived class

-------
Vptr --> | & derived: vfun1 |
-------
| & Base: vfun2 |
-------
| & Derived: vfun3 |
-------

Each time you create a class that contains a virtual function or derive a class from a class that contains a virtual function, the compiler creates
Vtable, as shown in. In this table, the compiler places
Or in its base class, all declared
The address of the virtual function. If this derived class does not declare
The virtual function is redefined, and the compiler uses the base class.
. (In
Derived's
In vtable,
This is the portal of vfun2 .) Then the compiler places
Vptr. When simple inheritance is used
Only one object exists.
Vptr.
Vptr
Must be initialized to point to the corresponding
Vtable
This occurs in the constructor.

Once
The vptr is initialized to point to the corresponding
Vtable, the object is
"Know
"What type is it. However, this kind of self-cognition is useful only when virtual functions are called.

My personal summary is as follows:

1
When a class contains a virtual function, the compiler creates
Vtable
. Each of its table items is the virtual function address of the class.

2
When defining the object of this derived class, first call the constructor of its base class, and then initialize
Vptr
And then call the constructor of the derived class (
From the binary perspective, the base class subclass is a large struct.
The four bytes starting with this pointer hold the header pointer of the virtual function. When executing a subclass constructor, you must first call the base class constructor,
This pointer is used as a parameter and is filled with
Vptr, return to the constructor of the subclass, and fill in
Vptr, overwrite
Vptr. Completed so far
Vptr initialization.
)


3. When implementing dynamic binding, you must use pointers or references instead of class objects. This is because a temporary base class object is generated by passing the value of a class object, while a pointer is used to access an external derived class object through a pointer.

Vptr
To access the virtual function of the derived class.

Vptr is often at the beginning of an object and can be easily obtained by the compiler.
Vptr value to determine
The location of the vtable.
Vptr always points
The starting address of the vtable, the virtual function of all base classes and its sub-classes
Number Address (except for virtual functions defined by subclass) in
The storage location in the vtable is always the same, as shown in the preceding figure.
Base class and
Derived class
Vtable
Vfun1 and
Vfun2 addresses are always stored in the same order. Compiler knows
Vfun1 is located
Vptr,
Vfun2 is located
Vptr + 1, so when using a base class pointer to call a virtual function, the compiler first obtains the pointer
Type information of the object (
Vptr), and then call the virtual function. For example
Base Class pointer
Pbase points to
Derived object, that
Pbase-> vfun2 () is translated by the compiler
Vptr + 1 calls because of virtual functions
The vfun2 address is
In vtable, the index is
1. Likewise,
Pbase-> vfun3 () is translated by the compiler
Call vptr + 2. This is the so-called late binding.

Let's take a look at the assembly code of virtual function calls to deepen our understanding.

Void test (base * pbase)
{
Pbase-> vfun2 ();
}

Int main (INT argc, char * argv [])
{
Derived TD;

Test (& TD );

Return 0;
}

The compilation code generated by derived TD; is as follows:

MoV dword ptr _ TD $ [esp + 24], offset flat :?? _ 7derived @ 6B @; derived: 'vftable'
According to the comments of the compiler
What is stored in PTR _ TD $ [esp + 24] is
Derived class
Vtable address.


The compilation code generated by test (& TD); is as follows:

Lea eax, dword ptr _ TD $ [esp + 24]
MoV dword ptr __$ ehrec $ [esp + 32], 0
Push eax
Call? Test @ yaxpavbase @ Z; Test
Call
The test function completes the following work: getting objects
The address of TD, press it on the stack, and then call
Test.

Pbase-> vfun2 (); The compilation code is as follows:

MoV ECx, dword ptr _ pbase $ [esp-4]
MoV eax, dword ptr [ECx]
Jmp dword ptr [eax + 4]
First retrieve from Stack
The object address pointed to by the pbase pointer is assigned
ECX, and then assign the address in the pointer variable starting with the object
Eax.
The value of eax is
The value of vptr, that is
The vtable address. Finally, the virtual function is called.
Vfun2 is located
The second location of the vtable, which is equivalent
Vptr + 1, each function pointer is
4 bytes long, so the last
The call is translated by the compiler
Jmp dword ptr [eax + 4]. If you call
Pbase-> vfun1 (), which should be compiled
Jmp dword ptr [eax].

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.