Explore the C + + object Model (i)

Source: Internet
Author: User

The birth of virtual function in C + + is for the realization of polymorphism. When a subclass overrides a virtual function of the parent class, when the parent class pointer invokes the overridden virtual function, if the parent pointer (or reference) points to the object of the parent class, the virtual function of the parent class is called, and if the parent pointer (or reference) points to the child class object, the virtual function of the subclass is called.

To understand the implementation of polymorphism, it is necessary to know the composition of the virtual function table .

"Note: The Code test environment in the article is Win7 64-bit VS2013"

First, we discuss a single class that contains virtual functions, that is, there is no inheritance relationship.

When a virtual function is contained in our class, the class instantiates an object whose members, in addition to their own member variables, will have one more pointer. This pointer is called the virtual table pointer , and he points to the virtual table maintained by our class object. The address of all virtual functions in a class is saved in a virtual table. The code is as follows:

Class B{public:b (): _val (1) {}virtual void fun1 () {cout << "void B::fun1 ()" << Endl;} virtual void fun2 () {cout << "void b::fun2 ()" << Endl;} void Fun3 () {cout << "void B::fun3 ()" << Endl;} Private:int _val;}; int main () {b b;cout << sizeof (b) << endl;//output is 8system ("pause"); return 0;}

Code Description: The constructor assigns a value of 1 to a class member variable, facilitates memory viewing, the member function has two virtual functions, a non-virtual function, a breakpoint is hit at return 0;

Then we switch to the Watch window,< the following > can be found, object B actually maintains two members, "__vfptr" and "_val", in the Memory Window "&b", get 0012cc74, that is __vfptr, the next is 00000001, that is our member _val. This also explains why sizeof (b) 's output is 8. no matter how many virtual functions there are, only one virtual table pointer is left in the class, and no more virtual functions are added, and the value of sizeof (b) is not changed .

In addition, you can see that the virtual table only holds virtual function addresses, non-virtual functions, and still belong to the entire class rather than the object.


650) this.width=650; "src=" Http://s5.51cto.com/wyfs02/M00/86/5B/wKiom1e9At7BsZajAACQewWnjEw250.png "title=" 1.png " alt= "Wkiom1e9at7bszajaacqewwnjew250.png"/>

Let's look again at the space __vfptr points to

650) this.width=650; "src=" Http://s4.51cto.com/wyfs02/M01/86/5A/wKioL1e9Bc2C4Gh-AADAMK6D200419.png "title=" 2.png " alt= "Wkiol1e9bc2c4gh-aadamk6d200419.png"/>

The first two are the addresses of my virtual functions, that is to say, there is a relationship between them as follows

650) this.width=650; "src=" Http://s2.51cto.com/wyfs02/M02/86/5A/wKioL1e9CCeCP8HWAAANxRKo_s0558.png "title=" 1.png " alt= "Wkiol1e9ccecp8hwaaanxrko_s0558.png"/>

To verify, here I reseal a function pointer, through the offset, to see if I can output the contents of the cout. The code is as follows:

typedef void (*p_fun) (), void Print_fun (p_fun* ppfun) {for (int i = 0;/* Ppfun[i]! = null*/i<2; i++) {ppfun[i] ();}} void Test () {b b; Print_fun ((p_fun*) (* (int*) &b));

The test is capable of outputting the contents of our function. More to say, the virtual table in front of the virtual function is the address, the final end of the item under different compiler is not the same, in the VS2013 environment, the last saved address is inaccessible, VS2008 environment, and finally to the end of 0x00000000, that is, null. So the print function Print_fun () in the For loop condition I made the modification. Of course, you can call a function more directly.

((p_fun*) (* (int*) &b)) [0] ()//((p_fun*) (* (int*) &b)) [1] ();

Next, we look at the virtual table in the single inheritance that contains the virtual function overrides

This gives a single-inheritance test code

class a{public:a (): _a_val (1) {} virtual void fun1 () { cout <<  "void a::fun1 ()" &NBSP;<<&NBSP;ENDL;} Virtual void fun2 () {cout <<  "void a::fun2 ()" &NBSP;<<&NBSP;ENDL;} protected:int _a_val;}; Class b:public a{public:b (): _b_val (2) {}virtual void fun1 () {cout <<  " VIRTUAL&NBSP;B::FUN1 () "&NBSP;<<&NBSP;ENDL;} VIRTUAL&NBSP;VOID&NBSP;FUN3 () {cout <<  "Virtual b::fun3 ()" &NBSP;<<&NBSP;ENDL;} Virtual void fun4 () {cout <<  "Virtual b::fun4 ()" &NBSP;<<&NBSP;ENDL;} protected:int _b_val;}; Void test () {b b;} 

Code Description: The parent Class A contains two virtual functions fun1 (), fun2 (), a member variable _a_val, a construction member variable of 1, subclass B has inherited a, rewrite the function fun1 (), adding two of its own virtual functions fun3 (), Fun4 (), member variable _b_val, and constructed as 2.

Next switch to the Debug window <, you can see that Class B instantiation object B actually maintains three members, "__vfptr", "_a_val", "_b_val", in the Memory window "&b", Get 0x009bcd48, Corresponds to the Watch window, __vfptr, followed by 0x00000001,0x00000002, which is the member variable _a_val,_b_val. If you go here to sizeof (b), the result should be 12.

650) this.width=650; "src=" Http://s1.51cto.com/wyfs02/M01/86/5B/wKiom1e9E3yBwdLCAACI65xOT4k400.png "title=" 2.png " alt= "Wkiom1e9e3ybwdlcaaci65xot4k400.png"/>

Next look at the space __vfptr points to

650) this.width=650; "src=" Http://s1.51cto.com/wyfs02/M02/86/5B/wKioL1e9FpeBQQ6EAACo_9bs3TM388.png "title=" 3.png " alt= "Wkiol1e9fpebqq6eaaco_9bs3tm388.png"/>

what you see in the watch is only two function addresses, but in the memory window you can see that the first four are together in memory, or very close to each other. In order to confirm, using just the printing function, but need to change the number of cycles, by the compiler's limit, here can only manually modify the number of cycles, see the most printing how many times the normal end, not the program crashes.

typedef void (*p_fun) (), void Print_fun (p_fun* ppfun) {for (int i = 0;/* Ppfun[i]! = null*/i<4; i++) {ppfun[i] ();}} void Test () {B b;//((p_fun*) (* (int*) &b)) [0] ();//((p_fun*) (* (int*) &b)) [1] ()//((p_fun*) (* (int*) &b)) [2] ();//((p_fun*) (* (int*) &b)) [3] (); Print_fun ((p_fun*) (* (int*) &b));

the test results can be printed up to four times and printed as follows:

650) this.width=650; "src=" Http://s1.51cto.com/wyfs02/M02/86/5B/wKioL1e9GYWjbJetAAAPfrUVfIo841.png "title=" 4.png " alt= "Wkiol1e9gywjbjetaaapfruvfio841.png"/>

* You can see the fun1 () function Quilt class B overrides, and the Fun2 () function inherits from the parent class. The resulting Watch window does not show virtual functions fun3 () and Fun4 () addresses, but in fact the newly created virtual function addresses of subclasses are also saved to the virtual table, and in the single inheritance process, the virtual functions of the subclasses and the virtual functions of the parent class are saved in the same virtual table , and No Child the virtual function of the class creates a separate virtual table .

There is a relationship:

650) this.width=650; "src=" Http://s2.51cto.com/wyfs02/M02/86/5B/wKioL1e9G9fTdIf2AAAY-IUqeFA475.png "title=" 5.png " alt= "Wkiol1e9g9ftdif2aaay-iuqefa475.png"/>

Next multi-inheritance in the object model

First give the test code, as follows

Class a{public:a (): _a_val (1) {}virtual void test1 () {cout <<  "A::test1 ()"   << endl;} Virtual void test2 () {cout <<  "A::test2 ()" &NBSP;&LT;&LT;&NBSP;ENDL;} protected:int _a_val;}; Class b{public:b (): _b_val (2) {}virtual void test1 () {cout <<  "B::test1 ()"   << endl;} Virtual void test3 () {cout <<  "B::test3 ()" &NBSP;&LT;&LT;&NBSP;ENDL;} protected:int _b_val;}; Class c{public:c (): _c_val (3) {}virtual void test1 () {cout <<  "C::test1 ()"   << endl;} Virtual void test4 () {cout <<  "C::test4 ()" &NBSP;&LT;&LT;&NBSP;ENDL;} protected:int _c_val;}; Class d:public a,public b,public c{public:d (): _d_val (4) {}virtual void test1 () { cout <<  "D::test1 ()" &NBSP;&LT;&LT;&NBSP;ENDL;} VIRTUAL&NBSP;VOID&NBSP;TEST5 () {cout <<  "D::test5 ()" &NBSP;&LT;&LT;&NBsp;endl;} protected:int _d_val;}; Void test () {d d;}

Code Description: First create three base classes, class A contains two virtual functions fun1 (), Fun2 (), class contains member variable _a_val, constructed as 1, class B contains two virtual functions fun1 (), Fun3 (), class contains member variable _b_val, constructed as 2; class C contains two virtual The function fun1 (), Fun4 (), the class contains the member variable _c_val, is constructed as 3, and the fourth class is created as a derived class D, together with inheriting Class A, Class B, Class C, containing virtual functions fun1 (), fun2 (), FUN1 () functions in the sub-class FUN1 () overrides, Also contains the member variable _d_val.

next switch to the Debug window <, you can see that Class D instantiation object D here maintains seven members, because there are three classes inherited, so there are three virtual table pointers "__vfptr", including member variables that inherit from three classes "_a_val", "_b_val", " _c_val "and its own member variable" _d_val ". In the Memory Window "&d", get the 0X013BDD04, corresponding to the Watch window, that is, the first class inherited virtual table pointer __vfptr, followed by 0x00000001, that is, the member variable _a_val, and so on, to get the second class of the virtual table pointer, and inherits from the second class's member variable, the third class's virtual table pointer, and the member variable that inherits from the third class, and the last item is the member variable of subclass D. If you go here to sizeof (b), the result should be 28.

650) this.width=650; "src=" Http://s1.51cto.com/wyfs02/M00/86/5C/wKiom1e9JVriQ2FoAAC-oKuJGJw759.png "title=" 6.png " alt= "Wkiom1e9jvriq2foaac-okujgjw759.png"/>

But here's the problem, where is the virtual function address of subclass D. Here we open multiple memory windows and list the contents of each virtual table pointer. <>

650) this.width=650; "Src=" Http://s3.51cto.com/wyfs02/M01/86/5D/wKiom1e9KUrxKtzEAAE98U7BP0c860.png " Title= "7.png" alt= "Wkiom1e9kurxktzeaae98u7bp0c860.png"/> can be seen, although the Watch window, a virtual table pointer under only two items, but the corresponding to the memory there are three items, it can be inferred that Subclasses separate virtual function addresses are stored in the virtual function table of the first inheriting subclass, and virtual functions that are not overridden do not create a single virtual function table.

In addition, you should see that each child inherits a parent class that contains a virtual function, and it will have one more virtual table pointer, possibly maintaining multiple virtual tables at the same time.

In other words, there is a correspondence relationship.


650) this.width=650; "src=" Http://s1.51cto.com/wyfs02/M02/86/5D/wKiom1e9Kx2SBPokAAAycopuGMk730.png "title=" 8.png " alt= "Wkiom1e9kx2sbpokaaaycopugmk730.png"/>

To mention a little more, the subclass inherits multiple parent classes, and the address of the parent virtual table is not necessarily contiguous

The function pointer is still used here to call my member function to verify. The code is as follows

typedef void (*p_fun) (), void Print_fun (p_fun* ppfun) {for (int i = 0; Ppfun[i]! = NULL; i++) {ppfun[i] ();}} void Test () {D D; Print_fun ((p_fun*) (* (int*) &d) cout << "-----------------------------------------" <<endl; Print_fun ((p_fun*) (* ((int*) &d+2)) cout << "-----------------------------------------" << Endl; Print_fun ((p_fun*) (* ((int*) &d+4)) cout << "-----------------------------------------" << Endl;}

The printing results are as follows:

650) this.width=650; "src=" Http://s2.51cto.com/wyfs02/M00/86/5D/wKioL1e9L5HSpC1HAAAUw_a-dec995.png "title=" 9.png " alt= "Wkiol1e9l5hspc1haaauw_a-dec995.png"/>

The function address of the subclass's proprietary virtual function test5 () is placed in the first inherited virtual table, and the Test1 () function is overridden by class D.

We understand the object model in C + + by virtual function table, understand that polymorphism is actually covered by virtual function, but through the above test, it can be found that the realization of polymorphism will undoubtedly bring about a decrease in efficiency (through two pointers to the reference can be accessed).

In addition to the point that should be seen, The process of polymorphic implementation is unsafe , although the contents of the virtual function table cannot be modified at will, it can always be accessed directly, which is a direct manifestation of insecurity.

The object model for diamond inheritance and the object model for Diamond virtual inheritance are mentioned in the next article.


------------------------------------------Muhuizz------------------------------------------

Http://11331490.blog.51cto.com

This article is from the "11321490" blog, please be sure to keep this source http://11331490.blog.51cto.com/11321490/1841930

Explore the C + + object Model (i)

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.