How C++ implements late binding:
The keyword virtual tells the
compiler it should not perform early binding. Instead, it should automatically
install all the mechanisms necessary to perform late binding.
To accomplish this, the
typical compiler1 creates a single table (called the VTABLE) for each class that contains virtual
functions.The compiler places the addresses of the virtual
functions for that particular class in the VTABLE.
In each class with virtual
functions,it secretly places a pointer, called the vpointer (abbreviated as
VPTR), which points to the VTABLE for that
object.
When you make a virtual
function call through a base-class pointer the
compiler quietly inserts code to fetch the VPTR and look up the function
address in the VTABLE, thus calling the correct function and causing late
binding to take place.
Virtual:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
class Shape
{
public:
virtual void draw(){cout<<"Shape
draw"<<endl;}
};
class Rectangle:public Shape
{
public:
void draw(){cout<<"Rectangle
draw"<<endl;}
};
class Circle:public Shape
{
public:
void draw()
{
cout<<"Circle draw"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
vector<Shape
*> shapelist;
Shape *s;
int choice = 1;
cout<<"enter 1 for rectangle ,2 for circle,0 for
exit"<<endl;
while(choice>0)
{
cin>>choice;
if(choice == 1)
{
Rectangle
R;
s=&R;
shapelist.push_back(s);
}
else if(choice == 2)
{
Circle
C;
s=&C;
shapelist.push_back(s);
}
else
break;
}
for(int i
=0;i<shapelist.size();i++)
{
shapelist[i]->draw();
}
return 0;
}
Run-time polymorphism: Definition: Keeping the behaviour
constant and switching the implementation at run-time is called Run-time
polymorphism.
Virtual Mechanism:
-
Compiler creates a v-table for each class that has atleast
one virtual function.
-
Only one v-table is created for each class irrespective of no
of objects.
-
Space cost: An extra
pointer per object + Extra pointer per each virtual method
-
Time cost: Normal function
call + Two extra fetches[one to get the value of the v-pointer and a second to
get the address of the method]
-
Virtual Function call:
class Base
{
public:
virtual
arbitrary_return_type Virt0{..parama..}
virtual
arbitrary_return_type Virt1{..parama..}
virtual
arbitrary_return_type Virt2{..parama..}
virtual
arbitrary_return_type Virt3{..parama..}
virtual
arbitrary_return_type Virt4{..parama..}
};
Step 1:
The compiler builds a static table containing function
pointer for each
Virtual function burying the table into static memory.
V-Table
FunctionPtr Base::__VTable[5] = {&Base::Virt0,
&Base::Virt1, &Base::Virt2, &Base::Virt3, &Base::Virt4};
Step 2:
The compiler adds a hidden pointer to each object of the
class Base called v-pointer.
Class Base
{
Public:
FunctionPtr*
__VPTR;
};
Step 3:
The compiler initializes this->__VPTR with in each
constructor.The idea is to cause each objects V-Pointer to point to its class’s
V-Table.
Base::Base(..params..)
:__VPTR(&Base::__VTable[0])
{
}
Example:
void MyCode(Base *p)
void MyCode(Base* p)
{ {
p->Virt3(); =======>> p-> __VPTR[3](p);
} }
0 comments:
Post a Comment