how c++ implements the polymorphism internally?

2019-02-09 14:52发布

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.

标签: c++ oop
4条回答
戒情不戒烟
2楼-- · 2019-02-09 15:08

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.

查看更多
可以哭但决不认输i
3楼-- · 2019-02-09 15:08

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);
查看更多
放荡不羁爱自由
4楼-- · 2019-02-09 15:14

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.

查看更多
看我几分像从前
5楼-- · 2019-02-09 15:23

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.

查看更多
登录 后发表回答