Page 1 of 1

Detail about How VPTR and Virtual table works Virtual function un C++ Rate Topic: ***** 2 Votes

#1 asadullah.ansari  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 3
  • View blog
  • Posts: 11
  • Joined: 16-January 08

Post icon  Posted 11 March 2008 - 12:48 AM

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

Is This A Good Question/Topic? 1
  • +

Replies To: Detail about How VPTR and Virtual table works

#2 nitin_c_c++  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 1
  • View blog
  • Posts: 13
  • Joined: 18-June 08

Posted 24 June 2008 - 10:51 PM

Explanation is very good and helpful.
Was This Post Helpful? 0
  • +
  • -

#3 adatapost  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 10-April 09

Posted 31 July 2009 - 11:51 PM

Many many Thanks to you. Superb article on vtable. I appreciate your knowledge.
Was This Post Helpful? 0
  • +
  • -

#4 javedn  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 17-October 09

Posted 17 October 2009 - 02:17 PM

wow...thats an amazing post on vptrs...
Was This Post Helpful? 0
  • +
  • -

#5 game_programmer  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 31-July 09

Posted 12 December 2009 - 07:17 AM

nice tutorial...

but what's FUN in d cOde... :P
Was This Post Helpful? 0
  • +
  • -

#6 hananr  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 04-January 10

Posted 04 January 2010 - 04:13 AM

class Test
{
  virtual void fun1() { cout << "Test::fun1" << endl; }
  virtual void func1() { cout << "Test::func1" << endl; }
  virtual void func2() { cout << this->a << this->b << endl; }

public:
  int a;
  int b;
  Test(int temp1 = 0, int temp2 = 0)
  {
	 a=temp1;
	 b=temp2; 
  }
  int getA()  
  {
	 return a;
  }
  int getB()  
  {
	 return b;
  }

};

typedef void(*Fun)(void);

int main() 
{
  Test obj(20,30);
  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();

  pFun = (Fun)*((int*)*(int*)(&obj+0)+2);
  pFun();

  return 0;

}




why when i call to pFun = (Fun)*((int*)*(int*)(&obj+0)+2);
its prints gibrish and not 20,30
Was This Post Helpful? 0
  • +
  • -

#7 Guest_srinivas*


Reputation:

Posted 13 May 2010 - 03:40 PM

Amazing stuff!!! Thanks a lot.
Was This Post Helpful? 0

#8 Guest_Pallavi Pathak*


Reputation:

Posted 31 July 2010 - 07:40 PM

thanks for the knowlwdge sharing!! this is really helpfull... thanks a lot!!!
Was This Post Helpful? 0

Page 1 of 1