Home Forums C Programming Detail about How VPTR and Virtual table works

Viewing 3 reply threads
  • Author
    Posts
    • #2072
      shalizy
      Participant

      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

      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:
      obj’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.
      Code: cpp

      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
      Code: cpp

      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:
      Code: cpp

      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

      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

      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:

      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

    • #3343
      deepaksancheti
      Participant

      I am sorry to say…
      But you r wrong at the very first example….

      It will simply occupy only 4 bytes…..
      How come 8 bytes?????

    • #3344
      valaraukar
      Participant

      int data1 has 4 byte
      and
      int data2 has 4 byte

      then total 8 byte

    • #3345
      Adetutu
      Participant

      Hi,

      Please confirm on which platform you are testing your program. On TurboC3 it has some diffrent output. I hope You are using gcc compiler on linux or solaris
Viewing 3 reply threads
  • The forum ‘C Programming’ is closed to new topics and replies.