The address of the virtual function is not necessarily saved in the virtual function table.

Source: Internet
Author: User

The address of the virtual function is not necessarily saved in the virtual function table.

I always thought that the address of the virtual function is saved in the virtual function table. I did not find this idea correct when I did a test a few days ago.

TestCode:

// The address of the virtual function is not necessarily saved in the virtual function table. CPP // 2010.8.19/* analysis: the final output result shows that all virtual functions are called through the derived virtual function table, it is found that the output of the first virtual function table (①) and the output of the second virtual function table (④) are the output of the same function, but the values in the virtual function table items are different. If the values of items in the virtual function table are the addresses of virtual functions, the values of the table items used to call the show () function in the two derived tables should be the same, but they are actually different. This indicates that the address of the virtual function is not necessarily saved in the virtual function table. This problem has never been encountered before (or noticed). Which of the two different values is the address of the derived: Show () function? Disassembly analysis .. // Code: blocks vs2005/2008 */# include <iostream> using namespace STD; Class basea {public: Virtual void show () {cout <"basea :: show () "<Endl ;}virtual void showaa () {cout <" basea: showaa () "<Endl ;}}; class baseb {public: virtual void show () {cout <"baseb: Show ()" <Endl;} virtual void showbb () {cout <"baseb: showbb () "<Endl ;}; class derived: Public basea, public baseb {public:/* override */void show () {cout <" derived: Show () "<Endl ;}virtual void showd () {cout <" derived: showd () "<Endl ;}; int main () {typedef void (_ thiscall * Fun) (void * pthis); // very important basea aobj; baseb bobj; derived dobj; /* basea object */INT ** P = (INT **) & aobj; cout <"----- basea Class Object -----" <Endl; cout <"① basea: \ t" <(int *) P [0] [0] <"\ t"; (fun) P [0] [0]) (p); cout <"② basea: \ t" <(int *) P [0] [1] <"\ t"; (fun) P [0] [1]) (p); cout <Endl; /* baseb object */P = (INT **) & bobj; cout <"----- baseb Class Object -----" <Endl; cout <"① baseb: \ t "<(int *) P [0] [0] <" \ t "; (fun) P [0] [0]) (p ); cout <"② baseb: \ t" <(int *) P [0] [1] <"\ t"; (fun) P [0] [1]) (p); cout <Endl; /* the virtual function table pointed to by the first virtual function table pointer of the derived object */P = (INT **) & dobj; cout <"----- derived class Object -----" <Endl; cout <"① derived: \ t" <(int *) P [0] [0] <"\ t"; (fun) P [0] [0]) (p); cout <"② derived: \ t "<(int *) P [0] [1] <" \ t "; (fun) P [0] [1]) (p ); cout <"③ derived: \ t" <(int *) P [0] [2] <"\ t"; (fun) P [0] [2]) (p); cout <Endl; /* the virtual function table pointed to by the second virtual function table pointer of the derived object */P = (INT **) (int *) (& dobj) + 1 ); cout <"④ derived: \ t" <(int *) P [0] [0] <"\ t"; (fun) P [0] [0]) (p); cout <"⑤ derived: \ t" <(int *) P [0] [1] <"\ t"; (fun) P [0] [1]) (p); System ("pause "); return 0;}/* ----- basea Class Object ----- ① basea: 00401320 basea: Show () ② basea: 00401350 basea: showaa () ----- baseb Class Object ----- ① baseb: 004013a0 baseb: Show () ② baseb: 004013d0 baseb: showbb () ----- derived class Object ----- ① derived: 00401440 derived :: show () ② derived: 00401350 basea: showaa () ③ derived: 00401470 derived: showd () ④ derived: 00405430 derived: Show () ⑤ derived: 004013d0 baseb :: showbb ()*/

Analysis

I. disassembly Analysis

Test results show that the address stored in the virtual function table may not be the address of the virtual function, but it must be associated with the virtual function, this is because the virtual function is successfully called through the table items in the virtual function table. Through disassembly analysis, the results show that the table items stored in the second virtual function table of the derived class are related to the derived: Show () function, not the address of the function. The analysis process is as follows:

1. The table items related to the first virtual function table and the derived: Show () function Save the address of the function.

Figure 1 call the show () function through the first virtual function table

After calling edX, follow up with F7, see:

 

Figure 2 derived: Show () function

2. The second virtual function table and the table items related to the derived: Show () function do not save the address of the function.

 

Figure 3 call the show () function through the second virtual function table

After calling edX, follow up with F7, see:

 

Figure 4 redirect

It can be found that the destination address to be redirected is the derived: Show () function.

 

3. Conclusion: The address of the derived: Show () function is saved in the first virtual function table. The address of the derived: Show () virtual function is not saved in the second virtual function table, but is indirectly associated with the virtual function address.

Ii. Reasons for not directly saving the function address

Now you know what is saved in the virtual function table. Another question is: Why does the address of the derived: Show () function not be saved in the second virtual function table, but the jump address needs to be saved and jumped over again? What is the purpose of this function?

This is related to the passing of the this pointer when calling a member function of the class.

Suppose there is such a statement:

Baseb * pb = & dobj;

Pb-> show ();

If there is no intermediate jump, call the show () function directly, then the passed this pointer is the address of the baseb class instance in the derived object, that is, the address of the second virtual function table. In this case, if you want to access the member variable in dobj, access through this pointer will fail. Derived: Show () may think that the address passed in is the address of the basea instance of the derived object. So we need the code in Figure 4. The table item in the second virtual function table stores the sub address. Before the jump, subtract ECx from 4. In this example, we can see that, minus 4, this pointer points to the dobj address (that is, the basea instance address ).

That is to say, the reason why the second virtual function table does not store the function address is to ensure that the this pointer is correct.

Cause prediction: You can call D: Show () through class A pointers, or call D: Show () through class B pointers. If this pointer is not adjusted, d: Show () when you want to access the member variable, this + offset value is used for addressing. In this case, an error occurs. So it must be adjusted.

Iii. When will this happen?

Another question is, when does the virtual function table not store the function address?

If you want to perform a comprehensive test, it is really a laborious task, so I guess this may be the case:

A derived class D has two base classes A and B. A defines the virtual function show (), B also defines the virtual function show (), in addition, Class D overrides the virtual function show (). The table items saved in the second virtual function table (Class B instance) in Class D are not D: Show () the virtual function address.

That is to say, when calling the show () function of class D Objects through class B pointers, you need to adjust this pointer.

PS: The above analysis uses vs2005/2008 as the compiler. However, the conclusion is also applicable to the GCC compiler.

 

Learning reference: http://topic.csdn.net/u/20091128/14/5a9ff412-560e-4214-8716-e269295f7028.html

2010.8.20

Cs_wuyg@126.com

-----------------

Note: This article does not consider jump to a table. -- 2010.9.5

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.