Virtual Pointer table : In c++ vtable is a mechanism to support runtime polymorphism.What it does is , it maintains addresses of , virtual functions defined in any class.
Need : consider a scenario in which you have one base class base and one derived class derived as below :
//Base class
class base
{
public:
base() { }
virtual void func(void) { std::cout<<"\n In Base func : "<<std::endl; }
virtual void func1(void) { std::cout<<"\n In Base func1: "<<std::endl; }
void func2(void) { std::cout<<"\n In Base func2: "<<std::endl; }
};
//derived class
class derived:public base
{
public:
derived() { }
void func2(void) { std::cout<<"\n In derived func2 : "<<std::endl; }
};
Note that func2 function in base class is not virtual
Now suppose i create two objects on heap like this :
base * b = new base;
base *d = new derived;
now i am inserting these objects in a vector of base class pointer types and sending to function print like this :
std::vector<base*> base_vec; //vector of base class pointer types
base_vec.push_back(b);
base_vec.push_back(d);
print(base_vec); // call function
And suppose my print function is implementated like :
void print(const std::vector<base *>& base_vec)
{
for(int i = 0;i<base_vec.size();++i)
{
base_vec[i]->func2();
}
}
Output generated after exucution of this function is :
In Base func2:
In Base func2:
But we were expecting that for second case , func2 of derived class should have been called , as we are pointing point d to derived object.
To overcome this , c++ provides concept of virtual functions. Virtual pointer table is maintained by the compiler to , keep track of virtual functions defined in any class . So that when , those functions overriden in derived called , it should update a entry in virtual pointer table as well.
Now make , func2 in base class , virtual i.e : virtual void func2(void) { std::cout<<"\n In Base func2: "<<std::endl; }
Output generated will be :
In Base func2:
In derived func2 :
Implementation : So big question is how compiler implements this behaviour internally , how it come to know which function to call for , base class , and which one to call for derived class.
What it does is , it maintains a table of , addresses of virtual functions which is called virtual pointer table .Whenever any class have any virtual function it , creates virtual pointer table for it, and adds virtual pointer , that is pointer to this virtual pointer table as a first hidden member of it.
So if you will declare any virtual function in any class , like :
class base
{
public:
base() { }
int a;
virtual void func(void) { std::cout<<"\n In Base func : "<<std::endl; }
}
And print it's size with sizeof operator ,it will be : 8 bytes , but if you willl remove virtual keyword , it will print 4 bytes.4 Extra bytes to hold pointer to virtual pointer table .
Note that it will always add 4 extra bytes only even if ,you declare more than one virtual functions inside class.
When you will override func function in derived class , virtual pointer table will update address of derived class function.So when it will be called with any base class pointer , appropriate function will be called .
Experiments : How can we convinced that any class with virtual function maintains virtual pointer table .
Do prove it , Consider original base class defination :
class base
{
public:
base() { }
virtual void func(void) { std::cout<<"\n In Base func : "<<std::endl; }
virtual void func1(void) { std::cout<<"\n In Base func1: "<<std::endl; }
void func2(void) { std::cout<<"\n In Base func2: "<<std::endl; }
};
It have two virtual functions func and func1 and one non-virtual function func2 .
Now i am creating one object of it on heap like this :
base * b = new base;
Now i am derefereencing the address of virtual pointer table like this :
int *ptr = (int*)b;
int *funcAdd = reinterpret_cast<int *>(*((int*)ptr+0)); //reinterpret_cast is used to cast out of any valid memory area
so , here funcAdd is base address of virtual pointer table .
Now since we will be accessing functions , i am declaring a fucntion pointer
void (*ptr_to_func) (void) ;
Now i have base address of virtual pointer table , i can enumerate all the virtual functions contained in it .
int i = 0;
while(true)
{
ptr_to_func = (void (*) (void)) (*(funcAdd+i));
if(ptr_to_func)
{
ptr_to_func();
++i;
}
else
break;
}
Output will be like this :
In Base func :
In Base func1:
Not however that it didn't printed func2 as it was not virtual .
Thats all :)
Full source code in c++:
#include <iostream>
#include <vector>
class base
{
public:
base() { }
virtual void func(void) { std::cout<<"\n In Base func : "<<std::endl; }
virtual void func1(void) { std::cout<<"\n In Base func1: "<<std::endl; }
void func2(void) { std::cout<<"\n In Base func2: "<<std::endl; }
};
class derived:public base
{
public:
derived() { }
void func2(void) { std::cout<<"\n In derived func2 : "<<std::endl; }
};
void print(const std::vector<base *>& base_vec)
{
for(int i = 0;i<base_vec.size();++i)
{
base_vec[i]->func2();
}
}
int main(void)
{
base * b = new base;
base *d = new derived;
std::vector<base*> base_vec;
base_vec.push_back(b);
base_vec.push_back(d);
//print(base_vec);
int *ptr = (int*)b;
int *funcAdd = reinterpret_cast<int *>(*((int*)ptr+0));
void (*ptr_to_func) (void) ;
int i = 0;
while(true)
{
ptr_to_func = (void (*) (void)) (*(funcAdd+i));
if(ptr_to_func)
{
ptr_to_func();
++i;
}
else
break;
}
int halt;
std::cin>>halt;
return 0;
}
No comments :
Post a Comment