Functions of C ++ virtual functions

Source: Internet
Author: User

Reprinted 1:

What is a virtual function? A virtual function is a function described by the keyword "Explain aul.

For example:

In this example, windowb and windowc do not exist at the same time, which is often used in practical applications to save memory.

Class sort wa

{

Public:

Virtual void draw (){};

};

 

Class Using WB: public using wa

{

Public:

Using WB (){};

Void draw ();

};

Class sort WC: Public sort wa

{

Public:

Windowc (){};

Void draw ();

};

 

Void required WB: Draw ()

{

Draw a circle;

}

Void merge WC: Draw ()

{

Draw a square;

}

When windowa is defined, you are not sure what the derived classes of windowb and windowc will draw in the draw function. In this case, the draw is defined as a virtual function, which is implemented in the derived class.

Speaking of this, the reader will ask: I will write draw in windowb and windowc, and I will write less of a kind of mongowa.

Yes, it's just a matter of writing. As you said, you will use it like this:

Required WB * B = new required WB;

B-> draw (); // draw a circle

Delete B;

Windowc * c = new windowc;

C-> draw (); // draw a square

Delete C;

I use pointers here. In the code above, B and C are two independent object pointers. But what should you do if there are dozens or hundreds of derived classes instead of one or two? How many hundred variables are defined in the header file?

No, it's time to use virtual functions:

Windowa * A = new windowsb;

A-> draw (); // draw a circle. The implementation of the draw function in windowb is called here.

If ()

Delete A; // The new value must be deleted.

Windowa * A = new windowc;

A-> draw (); // draw a square. The implementation of the draw function in windowc is called here.

If ()

Delete;

In the above Code, a implements a transit variable. As long as it is derived from megawa, I can assign a value to a, and B and C are both temporary variables. The number of derived classes of megawa is okay. I just need to define a pointer variable of megawa in the header file.

Reprinted from: http://www.cnblogs.com/goodcandle/archive/2005/09/21/241478


Reprinted 2:

The virtual function is associated with polymorphism, And the polymorphism is associated with inheritance. Therefore, this article is all about the inheritance level. Without inheritance, there is nothing to talk about.

The following is an understanding of the virtual functions of C ++.

1. What is a virtual function (if you don't know what is a virtual function, but want to know it urgently, you should start from here)

Simply put, member functions modified by virtual keywords are virtual functions. The role of virtual functions is explained in professional terms by implementing polymorphism. polymorphism separates interfaces from implementations. interpreting with image languages means implementing a common approach, however, different strategies are adopted due to individual differences. Let's take a look at a simple piece of code.

Class {

Public:

Void print () {cout <"This is a" <Endl ;}

};

Class B: Public {

Public:

Void print () {cout <"This is B" <Endl ;}

};

Int main () {// for future convenience, the main () code is called main1

A;

B;

A. Print ();

B. Print ();

}

Through the print () interface of Class A and Class B, we can see that these two classes adopt different policies due to individual differences, and the output results are also expected, this is a and this is B, respectively. But does this actually enable polymorphism? No. Another key to polymorphism is that all objects are operated by pointers or references to the base class. Now let's change the code in main.

Int main () {// main2

A;

B;

A * P1 = &;

A * P2 = & B;

P1-> Print ();

P2-> Print ();

}

Run the command to check the result. The problem is that P2 points to the Class B object but calls the print () function of Class A, which is not the expected result, to solve this problem, you need to use virtual functions.

Class {

Public:

Virtual void print () {cout <"This is a" <Endl ;}// it is now a virtual function.

};

Class B: Public {

Public:

Void print () {cout <"This is B" <Endl;} // do I need to add the keyword virtual in front of it?

};

Without a doubt, the print () member function of Class A has become a virtual function, so does the print () of Class B become a virtual function? The answer is yes. We only need to set the member functions of the base class to virtual, and the corresponding functions of the derived class will automatically become virtual functions. Therefore, print () of Class B is also a virtual function. If you need to use the virtual keyword to modify the corresponding function of the derived class, it is your own problem.

Run the main2 code again. The output result is this is a and this is B.

Now let's take a look at it. I will make a simple conclusion that the pointer to the base class will call its corresponding functions based on different class objects when operating on its polymorphism class objects, this function is a virtual function.

2. How can virtual functions be implemented? (If you haven't read the book "inside the C ++ Object Model" but are eager to know it, you should start from here)

How does a virtual function call its corresponding functions based on different objects? Now let's analyze the virtual functions. We first define two classes

Class A {// example code of the virtual function

Public:

Virtual void fun () {cout <1 <Endl ;}

Virtual void fun2 () {cout <2 <Endl ;}

};

Class B: Public {

Public:

Void fun () {cout <3 <Endl ;}

Void fun2 () {cout <4 <Endl ;}

};

Because these two classes have virtual functions, the compiler inserts a piece of data you don't know for them and creates a table for them. The data is called the vptr pointer and points to the table. The table is called vtbl, and each class has its own vtbl. vtbl is used to save the address of the virtual function in its own class. We can regard vtbl as an array in an image, each element in this array stores the address of the virtual function. See the figure below.

We can see that the two vtbl services Class A and Class B respectively. Now with this model, let's analyze the following code

A * P = new;

P-> fun ();

Undoubtedly, a: Fun () is called, but how is a: Fun () called? Does it jump directly to the code of a function like a normal function? No, in fact, this is the first thing to do is to retrieve the vptr value, which is the address of vtbl, and then come to vtbl based on this value, because the called function A: Fun () is the first virtual function, so the value in the first slot of vtbl is taken out. The value is the address of a: Fun (), and the function is called. Now we can see that, as long as the vptr is different, the vtbl pointing to is different, and different vtbl contains the virtual function address of the corresponding class, so the virtual function can complete its task.

For Class A and Class B, where are their vptr pointers stored? In fact, this pointer is placed in their respective instance objects. Because neither class A nor class B has data members, there is only one vptr pointer in their instance object. Through the above analysis, we now implement a piece of code to describe the simple model of the class with virtual functions.

# Include <iostream>

Using namespace STD;

// Add the above "virtual function sample code" here

Int main (){

Void (* Fun) (*);

A * P = new B;

Long lvptraddr;

Memcpy (& lvptraddr, P, 4 );

Memcpy (& fun, reinterpret_cast <long *> (lvptraddr), 4 );

Fun (P );

Delete P;

System ("pause ");

}

Compile and run it with VC or Dev-C ++ to see if the result is output 3. If not, the sun will surely come out from the west tomorrow. Start the analysis step by step.

Void (* Fun) (A *); This section defines a function pointer named fun and has a * type parameter, this function pointer will be used to save the function address retrieved from vtbl later.

A * P = new B; I don't know much about it. Forget it. I don't want to explain it.

Long lvptraddr; this long type variable will be used to save the vptr value later

Memcpy (& lvptraddr, P, 4); As mentioned earlier, their instance objects only have vptr pointers, therefore, we can safely copy the content in the 4 bytes memory referred to by P to lvptraddr. Therefore, the copied 4 bytes content is the value of vptr, that is, the vtbl address.

Now that we have the vtbl address, we can retrieve the content in the first slot of vtbl.

Memcpy (& fun, reinterpret_cast <long *> (lvptraddr), 4); extracts the content in the first slot of vtbl and stores it in function pointer fun. Note that lvptraddr contains the vtbl address, but lvptraddr is not a pointer, so we need to convert it into a pointer type first.

Fun (p); the function in the function address just retrieved is called here, that is, the function B: Fun () is called. You may find out why the parameter P exists, in fact, when calling a class member function, there will be a this pointer. This P is the this pointer, but in general calls, the compiler automatically handles it for you, and here you need to handle it yourself.

Delete P; and system ("pause"); I don't know much about this. Forget it.

What if I call B: fun2? Then retrieve the value in the second slot of vtbl.

Memcpy (& fun, reinterpret_cast <long *> (lvptraddr + 4), 4); why add 4? Because the length of a pointer is 4 bytes, add 4. Or memcpy (& fun, reinterpret_cast <long *> (lvptraddr) +); this is more in line with array usage, because lvptraddr is converted to the long * type, so + 1 is the length of sizeof (long)

3. Start with a piece of code

# Include <iostream>

Using namespace STD;

Class A {// example code 2 of the virtual function

Public:

Virtual void fun () {cout <"A: Fun" <Endl ;}

Virtual void fun2 () {cout <"A: fun2" <Endl ;}

};

Class B: Public {

Public:

Void fun () {cout <"B: Fun" <Endl ;}

Void fun2 () {cout <"B: fun2" <Endl ;}

}; // End // example code 2 of the virtual function

Int main (){

Void (A: * Fun) (); // defines a function pointer.

A * P = new B;

Fun = & A: fun;

(P-> * Fun )();

Fun = & A: fun2;

(P-> * Fun )();

Delete P;

System ("pause ");

}

Can you estimate the output result? If the estimated results are a: Fun and A: fun2, Congratulations. In fact, the real result is B: Fun and B: fun2. If you cannot figure it out, go on and look down. Tip: & A: Fun and & A: fun2 are the addresses of virtual functions actually obtained?

First, let's go back to the second part and use the code segment to get a "common" method to get the virtual function address.

# Include <iostream>

Using namespace STD;

// Add the above "virtual function sample code 2" here

Void callvirtualfun (void * pthis, int Index = 0 ){

Void (* funptr) (void *);

Long lvptraddr;

Memcpy (& lvptraddr, pthis, 4 );

Memcpy (& funptr, reinterpret_cast <long *> (lvptraddr) + index, 4 );

Funptr (pthis); // call

}

Int main (){

A * P = new B;

Callvirtualfun (p); // call the virtual function P-> fun ()

Callvirtualfun (P, 1); // call the virtual function P-> fun2 ()

System ("pause ");

}

Now we have a "general" callvirtualfun method.

What is the connection between this general method and the code at the beginning of the third part? Great contact. Since a: Fun () and a: fun2 () are virtual functions, & A: Fun and & A: fun2 do not obtain the function address, instead, it is the address of a piece of code that indirectly obtains the virtual function address. We regard this code as the callvirtualfun section. During compilation, the compiler will provide code similar to callvirtualfun. When you call a virtual function, you actually call the code similar to callvirtualfun first, after obtaining the virtual function address, call the virtual function to ensure polymorphism. At the same time, we all say that the efficiency of virtual functions is low because the code for obtaining the virtual function address is also called before the virtual function is called.

Note: The code in this article can be compiled using vc6 and Dev-C ++ 4.9.8.0 without any problems. Other compilers are not guaranteed. The analogy method can only be regarded as a model, because the lower-layer implementations of different compilers are different. For example, for this pointer, the GCC of Dev-C ++ is passed as a parameter through the pressure stack, and the VC compiler stores the address in ECx through the extract address. Therefore, these analogy methods cannot be used as concrete implementations.

Reprinted from: http://blog.csdn.net/wang7890/article/details/4042977

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.