Home Forums C Programming Details about VPTR, Virtual table, Virtual Function

Viewing 1 reply thread
  • Author
    Posts
    • #2061
      shalizy
      Participant

      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
      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::Fncadministrator2008-01-27 11:34:41

    • #3322
      bharat123
      Participant

      Hiin the example 10 of multiple inheritance ,i could’t understand the why the sizeof Derived class is 12 bytes, plz explain why this happening.
      waiting for ur reply……………

Viewing 1 reply thread
  • The forum ‘C Programming’ is closed to new topics and replies.