vtable和vptr

http://www.dreamincode.net/forums/topic/45816-detail-about-how-vptr-and-virtual-table-works/

 

这是一个相当牛的帖子。

1. vptr每个对象都会有一个,而vtable是每个类有一个

2. vptr指向了vtable

3. 在C++中,如果一个类有虚函数,那么这个对象的memory layout中就有特个vptr,且在最前面

4. 一个类中就算有多个虚函数,也只有一个vptr

5. 做多重继承,就是继承了多个父类时,就会有多个vptr

6. 看最后一个例子,当子类继承了多个父类,且自己又新加了虚函数,这个vptr是借用了第一个父类的?

 

 

Assumption: machine is 32-bit .
Here I am going to explain How Virtual table, Virtual pointer for Virtual functions are internally working.

First we have understand memory layout.

Example 1: How the class's memory layout

view source print ?
01 class Test
02 {
03    public:
04      int data1;
05      int data2;
06      int fun1();
07 };
08  
09 int main()
10 {
11    Test obj;
12    cout << "obj's Size = " << sizeof(obj) << endl;
13    cout << "obj 's Address = " << &obj << endl;
14    return 0;
15 }


Output:

Sobj's Size = 8
obj 's Address = 0012FF7C

Note: Any Plane member function does not take any memory.


Example 2: Memory Layout of Derived class

view source print ?
01 class Test
02 {
03 public:
04    int a;
05    int b;
06 };
07  
08 class dTest : public Test
09 {
10 public:
11    int c;
12 };
13  
14 int main()
15 {
16    Test obj1;
17    cout << "obj1's Size = " << sizeof(obj1) << endl;
18    cout << "obj1's Address = " << &obj1 << endl;
19    dTest obj2;
20    cout << "obj2's Size = " << sizeof(obj2) << endl;
21    cout << "obj2's Address = " << &obj2 << endl;
22    return 0;
23 }


OUTPUT:
obj1's Size = 8
obj1's Address = 0012FF78
obj2's Size = 12
obj2's Address = 0012FF6C

Example 3: Memory layout If we have one virtual function.

view source print ?
01 class Test
02 {
03 public:
04    int data;
05    virtual void fun1()
06    {
07      cout << "Test::fun1" << endl;
08    }
09 };
10  
11 int main()
12 {
13    Test obj;
14    cout << "obj's Size = " << sizeof(obj) << endl;
15    cout << "obj's Address = " << &obj << endl;
16    return 0;
17 }


OUTPUT:

obj's Size = 8
obj's Address = 0012FF7C

Note: Adding one virtual function in a class takes 4 Byte extra.

Example 4: More than one Virtual function

view source print ?
01 class Test
02 {
03 public:
04    int data;
05    virtual void fun1() { cout << "Test::fun1" << endl; }
06    virtual void fun2() { cout << "Test::fun2" << endl; }
07    virtual void fun3() { cout << "Test::fun3" << endl; }
08    virtual void fun4() { cout << "Test::fun4" << endl; }
09 };
10  
11 int main()
12   {
13    Test obj;
14    cout << "obj's Size = " << sizeof(obj) << endl;
15    cout << "obj's Address = " << &obj << endl;
16    return 0;
17   }


OUTPUT:

obj's Size = 8
obj's Address = 0012FF7C

Note: Adding more virtual functions in a class, no extra size taking i.e. Only one machine size taking(i.e. 4 byte)

Example 5:

view source print ?
01 class Test
02   {
03 public:
04    int a;
05    int b;
06    Test(int temp1 = 0, int temp2 = 0)
07    {
08       a=temp1;
09       b=temp2;
10    }
11    int getA() 
12    {
13       return a;
14    }
15    int getB() 
16    {
17       return b;
18    }
19    virtual ~Test();
20 };
21  
22 int main()
23 {
24    Test obj(5, 10);
25  
26 // Changing a and b
27    int* pInt = (int*)&obj;
28    *(pInt+0) = 100;  
29    *(pInt+1) = 200;  
30  
31    cout << "a = " << obj.getA() << endl;
32    cout << "b = " << obj.getB() << endl;
33    return 0;
34 }


OUTPUT:
a = 200
b = 10

If we Change the code as then

// Changing a and b
int* pInt = (int*)&obj;
*(pInt+1) = 100; // In place of 0
*(pInt+2) = 200; // In place of 1

OUTPUT:
a = 100
b = 200

Note: Who sits 1st place of Class : Answer is VPTR
VPTR - 1st placed in class and rest sits after it.



Example 6:

view source print ?
01 class Test
02 {
03    virtual void fun1()
04    {
05       cout << "Test::fun1" << endl;
06    }
07 };
08  
09 int main()
10 {
11    Test obj;
12    cout << "VPTR's Address " << (int*)(&obj+0) << endl;
13    cout << "VPTR's Value " << (int*)*(int*)(&obj+0) << endl;
14    return 0;
15 }


OUTPUT:

VPTR's Address 0012FF7C
VPTR's Value 0046C060

NOTE: This VPTR's value is a address of Virtual table. Lets see in next Example.

Example 7:

view source print ?
01 #include <iostream>
02 using namespace std;
03  
04 class Test
05   {
06     virtual void fun1()
07     {
08      cout << "Test::fun1" << endl;
09     }
10 };
11 typedef void (*Fun)(void);
12  
13 int main()
14 {
15    Test obj;
16    cout << "VPTR's Address " << (int*)(&obj+0) << endl;
17    cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << endl; // Value of VPTR
18    cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl;
19     
20    Fun pFun = (Fun)*(int*)*(int*)(&obj+0);   // calling Virtual function
21    pFun();
22    return 0;
23 }


OUTPUT:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1


Example 8:

view source print ?
01 class Test
02 {
03    virtual void fun1() { cout << "Test::fun1" << endl; }
04    virtual void func1() { cout << "Test::func1" << endl; }
05 };
06  
07 int main()
08   {
09    Test obj;
10  
11    cout << "VPTR's Address " << (int*)(&obj+0) << endl;
12    cout << "VIRTUAL TABLE 's Address" << (int*)*(int*)(&obj+0) << endl;
13  
14    // Calling Virtual table functions
15    cout << "Value at 1st entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+0) << endl;
16    cout << "Value at 2nd entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+1) << endl;
17  
18    return 0;
19 }


OUTPUT:

VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Value at 2nd entry of VIRTUAL TABLE 004012


Example :9

view source print ?
01 class Test
02 {
03    virtual void fun1() { cout << "Test::fun1" << endl; }
04    virtual void func1() { cout << "Test::func1" << endl; }
05 };
06  
07 typedef void(*Fun)(void);
08  
09 int main()
10 {
11    Test obj;
12    Fun pFun = NULL;
13     
14    // calling 1st virtual function
15    pFun = (Fun)*((int*)*(int*)(&obj+0)+0);
16    pFun();
17  
18    // calling 2nd virtual function
19    pFun = (Fun)*((int*)*(int*)(&obj+0)+1);
20    pFun();
21  
22    return 0;
23 }


OUTPUT:

Test::fun1
Test::func1

Example 10: multiple Inheritance

view source print ?
01 class Base1
02 {
03 public:
04    virtual void fun();
05 };
06  
07 class Base2
08 {
09 public:
10    virtual void fun();
11 };
12  
13 class Base3
14 {
15 public:
16    virtual void fun();
17 };
18  
19 class Derive : public Base1, public Base2, public Base3
20 {
21 };
22  
23 int main()
24 {
25    Derive obj;
26    cout << "Derive's Size = " << sizeof(obj) << endl;
27    return 0;
28 }


OUTPUT:

Derive's Size = 12


Example 11: Calling Virtual Functions in case of Multiple Inheritance

view source print ?
01 class Base1
02 {
03    virtual void fun1() { cout << "Base1::fun1()" << endl; }
04    virtual void func1() { cout << "Base1::func1()" << endl; }
05 };
06  
07 class Base2 {
08    virtual void fun1() { cout << "Base2::fun1()" << endl; }
09    virtual void func1() { cout << "Base2::func1()" << endl; }
10 };
11  
12 class Base3 {
13    virtual void fun1() { cout << "Base3::fun1()" << endl; }
14    virtual void func1() { cout << "Base3::func1()" << endl; }
15 };
16  
17 class Derive : public Base1, public Base2, public Base3
18 {
19 public:
20    virtual void Fn()
21    {
22    cout << "Derive::Fn" << endl;
23    }
24    virtual void Fnc()
25    {
26    cout << "Derive::Fnc" << endl;
27    }
28 };
29  
30 typedef void(*Fun)(void);
31  
32 int main()
33 {
34    Derive obj;
35    Fun pFun = NULL;
36     
37    // calling 1st virtual function of Base1
38    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
39    pFun();
40  
41    // calling 2nd virtual function of Base1
42    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
43    pFun();
44  
45    // calling 1st virtual function of Base2
46    pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);
47    pFun();
48  
49    // calling 2nd virtual function of Base2
50    pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);
51    pFun();
52  
53    // calling 1st virtual function of Base3
54    pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);
55    pFun();
56  
57    // calling 2nd virtual function of Base3
58    pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);
59    pFun();
60  
61    // calling 1st virtual function of Drive
62    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
63    pFun();
64  
65    // calling 2nd virtual function of Drive
66    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
67    pFun();
68  
69    return 0;
70 }


OUTPUT:

Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Drive::Fn
Drive::Fnc


By
Asadullah Ansari

 

你可能感兴趣的:(function,layout,table,Class,fun,output)