как с ++ реализует полиморфизм внутренне? - PullRequest
7 голосов
/ 31 января 2010

Уважаемый сэр!

Я должен сказать вам, что я знаю и что я не знаю о заданном вопросе, чтобы вы могли обратиться к слабой области моего понимания.

Я знаю, что C ++ реализует полиморфизм с помощью Vtable, который является массивом указателей. каждый указатель указывает на виртуальную функцию класса, у каждого класса в иерархии есть vtable. теперь предположим, что у меня есть следующий класс

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;
     }
};

теперь предположим, что я пишу в основной программе

person *ptr;
ptr=new teacher(16,"Zia");
ptr->show();

Теперь я запутался в этой точке, вызов перейдет к функции show базового класса, теперь, поскольку это виртуальная функция, поэтому она вызывает функцию подходящего типа. Я знаю, что я не прав здесь. Я запутался, что будет последовательность звонков. Какова роль Vtable и как она работает, уточните.

Ответы [ 4 ]

8 голосов
/ 31 января 2010

Поскольку show объявлено virtual в классе person, компилятор не будет жестко кодировать вызов метода, как это было бы для невиртуального метода, вместо этого он скомпилирует поиск в V таблица для получения правильной функции.

Таким образом, ptr->show() будет скомпилировано как ptr->vtable['show'](), что означает «найти указатель функции, соответствующий методу show, и выполнить его».

Поскольку во время выполнения ptr указывает на объект класса teacher, слот vtable для show содержит указатель на метод show в классе teacher. Вот почему правильный метод выполняется.

На самом деле поиск в V-таблице выполняется не с использованием строк, а с использованием числовых идентификаторов методов, чтобы быть максимально быстрым.

7 голосов
/ 31 января 2010

Думаю, вам следует обратить внимание на книгу Стэнли Б. Липпмана " Внутри объектной модели C ++ ".

Давайте посмотрим на внутреннюю презентацию для ваших классов:

Виртуальный стол для человека и учителя

|---------------|  +---> |------------------------|
|  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"         |
                          |-------------------------|               

В общем, мы не знаем точный тип адреса ptr объекта при каждом вызове show (). Однако мы знаем, что через ptr мы можем получить доступ к виртуальной таблице, связанной с классом объекта.

Хотя мы не знаем, какой экземпляр show () вызывать, мы знаем, что адрес каждого экземпляра содержится в слоте 2.

Эта информация позволяет компилятору внутренне преобразовать вызов в

( *ptr->vptr[ 2 ] )( ptr ); 

В этом преобразовании vptr представляет внутренне сгенерированный указатель виртуальной таблицы, вставленный в каждый объект класса, а 2 представляет назначенный слот show () в виртуальной таблице, связанной с иерархией Point. Единственное, что нам нужно сделать во время выполнения, это вычислить динамический тип ptr (и соответствующий vtable) с использованием RTTI.

6 голосов
/ 31 января 2010
Язык

C ++ не определяет реализации полиморфизма, даже vtable. Это зависит от компиляторов.
Одна из возможных реализаций - та, о которой упоминал Винсент Роберт .

3 голосов
/ 31 января 2010

Стандарт ничего не говорит о том, как реализовать полиморфизм. Один класс один vtbl и один объект один vptr является наиболее популярным способом. Я надеюсь, что следующий псевдокод будет полезен.

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...