Detail About How VPTR And Virtual Table Works
this article is about how vptr and virtual table works,and it comes from http://www.dreamincode.net/forums/topic/45816-detail-about-how-vptr-and-virtual-table-works/
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
class Test { public: int data1; int data2; int fun1(); }; int main() { Test obj; cout << "obj's Size = " << sizeof(obj) << endl; cout << "obj 's Address = " << &obj << endl; return 0; }
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
class Test { public: int a; int b; }; class dTest : public Test { public: int c; }; int main() { Test obj1; cout << "obj1's Size = " << sizeof(obj1) << endl; cout << "obj1's Address = " << &obj1 << endl; dTest obj2; cout << "obj2's Size = "<< sizeof(obj2) << endl; cout << "obj2's Address = "<< &obj2 << endl; return 0; }
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.
class Test { public: int data; virtual void fun1() { cout << "Test::fun1" << endl; } }; int main() { Test obj; cout << "obj's Size = " << sizeof(obj) << endl; cout << "obj's Address = " << &obj << endl; return 0; }
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
class Test { public: int data; virtual void fun1() { cout << "Test::fun1" << endl; } virtual void fun2() { cout << "Test::fun2" << endl; } virtual void fun3() { cout << "Test::fun3" << endl; } virtual void fun4() { cout << "Test::fun4" << endl; } }; int main() { Test obj; cout << "obj's Size = " << sizeof(obj) << endl; cout << "obj's Address = " << &obj << endl; return 0; }
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:
class Test { public: int a; int b; Test(int temp1 = 0, int temp2 = 0) { a=temp1; b=temp2; } int getA() { return a; } int getB() { return b; } virtual ~Test(); }; int main() { Test obj(5, 10); // Changing a and b int* pInt = (int*)&obj; *(pInt+0) = 100; *(pInt+1) = 200; cout << "a = " << obj.getA() << endl; cout << "b = " << obj.getB() << endl; return 0; }
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:
class Test { virtual void fun1() { cout << "Test::fun1" << endl; } }; int main() { Test obj; cout << "VPTR's Address " << (int*)(&obj+0) << endl; cout << "VPTR's Value " << (int*)*(int*)(&obj+0) << endl; return 0; }
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:
#include <iostream> using namespace std; class Test { virtual void fun1() { cout << "Test::fun1" << endl; } }; typedef void (*Fun)(void); int main() { Test obj; cout << "VPTR's Address " << (int*)(&obj+0) << endl; cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << endl; // Value of VPTR cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl; Fun pFun = (Fun)*(int*)*(int*)(&obj+0); // calling Virtual function pFun(); return 0; }
OUTPUT:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1
Example 8:
class Test { virtual void fun1() { cout << "Test::fun1" << endl; } virtual void func1() { cout << "Test::func1" << endl; } }; int main() { Test obj; cout << "VPTR's Address " << (int*)(&obj+0) << endl; cout << "VIRTUAL TABLE 's Address"<< (int*)*(int*)(&obj+0) << endl; // Calling Virtual table functions cout << "Value at 1st entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+0) << endl; cout << "Value at 2nd entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+1) << endl; return 0; }
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
class Test { virtual void fun1() { cout << "Test::fun1" << endl; } virtual void func1() { cout << "Test::func1" << endl; } }; typedef void(*Fun)(void); int main() { Test obj; Fun pFun = NULL; // calling 1st virtual function pFun = (Fun)*((int*)*(int*)(&obj+0)+0); pFun(); // calling 2nd virtual function pFun = (Fun)*((int*)*(int*)(&obj+0)+1); pFun(); return 0; }
OUTPUT:
Test::fun1
Test::func1
Example 10: multiple Inheritance
class Base1 { public: virtual void fun(); }; class Base2 { public: virtual void fun(); }; class Base3 { public: virtual void fun(); }; class Derive : public Base1, public Base2, public Base3 { }; int main() { Derive obj; cout << "Derive's Size = " << sizeof(obj) << endl; return 0; }
OUTPUT:
Derive's Size = 12
Example 11: Calling Virtual Functions in case of Multiple Inheritance
class Base1 { virtual void fun1() { cout << "Base1::fun1()" << endl; } virtual void func1() { cout << "Base1::func1()" << endl; } }; class Base2 { virtual void fun1() { cout << "Base2::fun1()" << endl; } virtual void func1() { cout << "Base2::func1()" << endl; } }; class Base3 { virtual void fun1() { cout << "Base3::fun1()" << endl; } virtual void func1() { cout << "Base3::func1()" << endl; } }; class Derive : public Base1, public Base2, public Base3 { public: virtual void Fn() { cout << "Derive::Fn" << endl; } virtual void Fnc() { cout << "Derive::Fnc" << endl; } }; typedef void(*Fun)(void); int main() { Derive obj; Fun pFun = NULL; // calling 1st virtual function of Base1 pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0); pFun(); // calling 2nd virtual function of Base1 pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1); pFun(); // calling 1st virtual function of Base2 pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0); pFun(); // calling 2nd virtual function of Base2 pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1); pFun(); // calling 1st virtual function of Base3 pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0); pFun(); // calling 2nd virtual function of Base3 pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1); pFun(); // calling 1st virtual function of Drive pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2); pFun(); // calling 2nd virtual function of Drive pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3); pFun(); return 0; }
OUTPUT:
Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Drive::Fn
Drive::Fnc
By
Asadullah Ansari
others about vptr and virtual :
(1)http://blog.csdn.net/haoel/article/details/1948051
(2)http://topic.csdn.net/u/20120413/22/4691a553-ab7d-4a5b-b14b-757a2676c328.html?64575
(3)http://blog.csdn.net/hairetz/article/details/4137000
(4)http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/