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:
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
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:
Code: cpp
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:
Code: cpp
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
Code: cpp
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
Code: cpp
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
Code: cpp
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
Asadullah Ansari
( Trueth can'nt be Changed)