Respected Sir!
i should tell you that what i know and what i don't know about the asked question so that you can address the weak area of my understanding.
i know that c++ implements the polymorphism by using the Vtable which is array of pointers
each pointer points to the virtual function of the class, each class in the hierarchy has a vtable. now suppose i have the following class
class person
{
char name[20];
public:
person(char* pname)
{
strcpy(name,pname);
}
virtual void show()
{
cout<<"inside person show method, Name: "<<name;
}
};
class teacher:public person
{
int scale;
teacher(char*pname, int s):person(pname)
{
scale=s;
}
void show()
{
cout<<"inside the teacher show method, Scale: "<<scale;
}
};
now suppose i write in main program
person *ptr;
ptr=new teacher(16,"Zia");
ptr->show();
now i am confuse at this point, the call will go to the show function of the base class, now as it is a virtual function so it inturn calls the approprite function. i know i am wrong here. i am confused that what would be the sequence of calls. What is the role of Vtable and how it works please elaborate.
I think you should draw attention to Stanley B. Lippman's book "Inside C++ object model".
Lets look for internal presentation for your classes:
Virtual Table for person and teacher
|---------------| +---> |------------------------|
| name | | | "type_info" for person |
|---------------| | |------------------------|
|__vptr__person |--+ | "person::~person" |
|---------------| |------------------------|
person p; | "person::show" |
|------------------------|
|----------------| +---> |-------------------------|
|person subobject| | | "type_info" for teacher |
|----------------| | |-------------------------|
|__vptr__teacher |--+ | "teacher::~teacher" |
|----------------| |-------------------------|
teacher t; | "teacher::show" |
|-------------------------|
In general, we don't know the exact type of the object ptr addresses at each invocation of show(). We do know, however, that through ptr we can access the virtual table associated with the object's class.
Although we don't know which instance of show() to invoke, we know that each instance's address is contained in slot 2.
This information allows the compiler to internally transform the call into
( *ptr->vptr[ 2 ] )( ptr );
In this transformation, vptr represents the internally generated virtual table pointer inserted within each class object and 2 represents show()'s assigned slot within the virtual table associated with the Point hierarchy. The only thing we need to do in runtime is compute ptr's dynamic type (and appropriate vtable) using RTTI.
Since show
is declared virtual
in the person
class, the compiler will not hard-code the method call like it would do for a non-virtual method, it will instead compile a lookup in the V-table in order to retrieve the right function.
So ptr->show()
will be compiled as ptr->vtable['show']()
which means "search the function pointer that corresponds to method show
and execute it".
Since at runtime, ptr
points to an object of class teacher
, the vtable slot for show
contains a pointer to the method show
in the class teacher
. That is why the right method is executed.
Actually, lookup in the V-table is not done using strings but using numeric method identifiers in order to be as fast as possible.
C++ language doesn't define polymorphism implementations, not even the vtable
. That's up to the compilers.
One possible implementation is the one mentioned by Vincent Robert.
The Standard says nothing about how to implements the polymorphism. One class one vtbl and one object one vptr is the most popular way.
I hope the following pseudocode would be helpful.
typedef struct {
void (*show)(void* self);
// more
} person_vtbl;
typedef struct {
person_vtbl* vtbl;
char name[20];
} person;
void person_show(void* self) {
cout<<"inside ... "<<static_cast<person*>(self)->name;
}
// more
static person_vtbl person_vtbl_ = { &person_show }; // vtbl for person class
void person_ctor(void* self, char const* name) {
person* p = static_cast<person*>(self);
strcpy(p->name, name);
p->vtbl = &person_vtbl // vptr of person object
}
typedef struct {
person base;
int scale;
} teacher;
void teacher_show(void* self) {
cout<<"inside the tearch ... "<<static_cast<teacher*>(self)->scale;
}
static person_vtbl teacher_vtbl_ = { &teacher_show };
void teacher_ctor(void* self, char const* name, int s) {
teacher* t = static_cast<teacher*>(self);
person_ctor(&t->base, name); // construct base part
t->scale = s; // construct teacher part
t->vtbl = &teacher_vtbl_; // vptr of teacher object
}
// construct teacher :
// person* ptr = new teacher("Zia", 16);
teacher* tmp = static_cast<teacher*>( malloc( sizeof *tmp );
teacher_ctor(tmp, "Zia", 16); // vptr of tmp points to teacher_vtbl_
person* ptr = &tmp->base;
// call virtual function though pointer
// ptr->show()
ptr->vptr->show(ptr); // call teacher_show(ptr);