Detail about How VPTR and Virtual table works

Assumption: 32-bit Machine.
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
Code: cpp

  1. class Test
  2. {
  3. public:
  4. int data1;
  5. int data2;
  6. int fun1();
  7. };
  8. int main()
  9. {
  10. Test obj;
  11. cout << "obj's Size = " << sizeof(obj) <<>
  12. cout << "obj 's Address = " << &obj <<>
  13. return 0;
  14. }
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
Code: cpp

  1. class Test
  2. {
  3. public:
  4. int a;
  5. int b;
  6. };
  7. class dTest : public Test
  8. {
  9. public:
  10. int c;
  11. };
  12. int main()
  13. {
  14. Test obj1;
  15. cout << "obj1's Size = " << sizeof(obj1) <<>
  16. cout << "obj1's Address = " << &obj1 <<>
  17. dTest obj2;
  18. cout << "obj2's Size = "<< sizeof(obj2) <<>
  19. cout << "obj2's Address = "<< &obj2 <<>
  20. return 0;
  21. }
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.
Code: cpp



  1. class Test
  2. {
  3. public:
  4. int data;
  5. virtual void fun1()
  6. {
  7. cout << "Test::fun1" <<>
  8. }
  9. };
  10. int main()
  11. {
  12. Test obj;
  13. cout << "obj's Size = " << sizeof(obj) <<>
  14. cout << "obj's Address = " << &obj <<>
  15. return 0;
  16. }
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

Code: cpp

  1. class Test
  2. {
  3. public:
  4. int data;
  5. virtual void fun1() { cout << "Test::fun1" << class="br0" style="color: gray; font-weight: bold; ">}
  6. virtual void fun2() { cout << "Test::fun2" << class="br0" style="color: gray; font-weight: bold; ">}
  7. virtual void fun3() { cout << "Test::fun3" << class="br0" style="color: gray; font-weight: bold; ">}
  8. virtual void fun4() { cout << "Test::fun4" << class="br0" style="color: gray; font-weight: bold; ">}
  9. };
  10. int main()
  11. {
  12. Test obj;
  13. cout << "obj's Size = " << sizeof(obj) <<>
  14. cout << "obj's Address = " << &obj <<>
  15. return 0;
  16. }
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:

Code: cpp


  1. class Test
  2. {
  3. public:
  4. int a;
  5. int b;
  6. Test(int temp1 = 0, int temp2 = 0)
  7. {
  8. a=temp1 ;
  9. b=temp2 ;
  10. }
  11. int getA()
  12. {
  13. return a;
  14. }
  15. int getB()
  16. {
  17. return b;
  18. }
  19. virtual ~Test();
  20. };
  21. int main()
  22. {
  23. Test obj(5, 10);
  24. // Changing a and b
  25. int* pInt = (int*)&obj;
  26. *(pInt+0) = 100;
  27. *(pInt+1) = 200;
  28. cout << "a = " << class="me1">getA() <<>
  29. cout << "b = " << class="me1">getB() <<>
  30. return 0;
  31. }
OUTPUT:
a = 200
b = 10

If we Change the code as then
Code: Cpp


// 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:

Code: cpp


  1. class Test
  2. {
  3. virtual void fun1()
  4. {
  5. cout << "Test::fun1" <<>
  6. }
  7. };
  8. int main()
  9. {
  10. Test obj;
  11. cout << "VPTR's Address " << (int*)(&obj+0) <<>
  12. cout << "VPTR's Value " << (int*)*(int*)(&obj+0) <<>
  13. return 0;
  14. }
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:

Code: cpp


  1. class Test
  2. {
  3. virtual void fun1()
  4. {
  5. cout << "Test::fun1" <<>
  6. }
  7. };
  8. typedef void (*Fun)(void);
  9. int main()
  10. {
  11. Test obj;
  12. cout << "VPTR's Address " << (int*)(&obj+0) <<>
  13. cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << class="co1" style="color: green; ">// Value of VPTR
  14. cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) <<>
  15. Fun pFun = (Fun)*(int*)*(int*)(&obj+0); // calling Virtual function
  16. pFun();
  17. return 0;
  18. }
OUTPUT:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1


Example 8:

Code: cpp

  1. class Test
  2. {
  3. virtual void fun1() { cout << "Test::fun1" << class="br0" style="color: gray; font-weight: bold; ">}
  4. virtual void func1() { cout << "Test::func1" << class="br0" style="color: gray; font-weight: bold; ">}
  5. };
  6. int main()
  7. {
  8. Test obj;
  9. cout << "VPTR's Address " << (int*)(&obj+0) <<>
  10. cout << "VIRTUAL TABLE 's Address"<< (int*)*(int*)(&obj+0) <<>
  11. // Calling Virtual table functions
  12. cout << "Value at 1st entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+0) <<>
  13. cout << "Value at 2nd entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+1) <<>
  14. return 0;
  15. }

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

Code: cpp

  1. class Test
  2. {
  3. virtual void fun1() { cout << "Test::fun1" << class="br0" style="color: gray; font-weight: bold; ">}
  4. virtual void func1() { cout << "Test::func1" << class="br0" style="color: gray; font-weight: bold; ">}
  5. };
  6. typedef void(*Fun)(void);
  7. int main()
  8. {
  9. Test obj;
  10. Fun pFun = NULL;
  11. // calling 1st virtual function
  12. pFun = (Fun)*((int*)*(int*)(&obj+0)+0);
  13. pFun();
  14. // calling 2nd virtual function
  15. pFun = (Fun)*((int*)*(int*)(&obj+0)+1);
  16. pFun();
  17. return 0;
  18. }
OUTPUT:

Test::fun1
Test::func1

Example 10: multiple Inheritance

Code: cpp

  1. class Base1
  2. {
  3. public:
  4. virtual void fun();
  5. };
  6. class Base2
  7. {
  8. public:
  9. virtual void fun();
  10. };
  11. class Base3
  12. {
  13. public:
  14. virtual void fun();
  15. };
  16. class Derive : public Base1, public Base2, public Base3
  17. {
  18. };
  19. int main()
  20. {
  21. Derive obj;
  22. cout << "Derive's Size = " << sizeof(obj) <<>
  23. return 0;
  24. }
OUTPUT:

Derive's Size = 12


Example 11: Calling Virtual Functions in case of Multiple Inheritance
Code: cpp
  1. class Base1
  2. {
  3. virtual void fun1() { cout << "Base1::fun1()" << class="br0" style="color: gray; font-weight: bold; ">}
  4. virtual void func1() { cout << "Base1::func1()" << class="br0" style="color: gray; font-weight: bold; ">}
  5. };
  6. class Base2 {
  7. virtual void fun1() { cout << "Base2::fun1()" << class="br0" style="color: gray; font-weight: bold; ">}
  8. virtual void func1() { cout << "Base2::func1()" << class="br0" style="color: gray; font-weight: bold; ">}
  9. };
  10. class Base3 {
  11. virtual void fun1() { cout << "Base3::fun1()" << class="br0" style="color: gray; font-weight: bold; ">}
  12. virtual void func1() { cout << "Base3::func1()" << class="br0" style="color: gray; font-weight: bold; ">}
  13. };
  14. class Derive : public Base1, public Base2, public Base3
  15. {
  16. public:
  17. virtual void Fn()
  18. {
  19. cout << "Derive::Fn" <<>
  20. }
  21. virtual void Fnc()
  22. {
  23. cout << "Derive::Fnc" <<>
  24. }
  25. };
  26. typedef void(*Fun)(void);
  27. int main()
  28. {
  29. Derive obj;
  30. Fun pFun = NULL;
  31. // calling 1st virtual function of Base1
  32. pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
  33. pFun();
  34. // calling 2nd virtual function of Base1
  35. pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
  36. pFun();
  37. // calling 1st virtual function of Base2
  38. pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);
  39. pFun();
  40. // calling 2nd virtual function of Base2
  41. pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);
  42. pFun();
  43. // calling 1st virtual function of Base3
  44. pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);
  45. pFun();
  46. // calling 2nd virtual function of Base3
  47. pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);
  48. pFun();
  49. // calling 1st virtual function of Drive
  50. pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
  51. pFun();
  52. // calling 2nd virtual function of Drive
  53. pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
  54. pFun();
  55. return 0;
  56. }

OUTPUT:

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