2012-06-03 3 views
0

Я не уверен, что это документировано где угодно. Мы все знаем в случае виртуальных функций, каждый класс содержит vptr, указатель на массив указателей функций, называемых виртуальной таблицей. Я хочу знать, что такое прототип vptr. Для бывшего, если класса объявлен следующим образом,C++: прототип виртуального указателя

class A 
{ 
    int a; 
    public: A(){} 
    virtual void display(); 
    virtual void setValue(int x); 
}; 

Теперь мы имеем два указателя на функцию в виртуальных таблицах класса А. Как один vptr способен из двух определений разного прототипа?

Пожалуйста, дайте мне знать, если мое понимание неверно.

Thx! Rahul.

+0

Возможный дубликат [Что такое структура виртуальных таблиц в C++?] (Http://stackoverflow.com/questions/5868431/what-is-the-structure-of-virtual-tables-in-c) –

ответ

3

vptr - это деталь реализации, и, как таковая, у нее нет прототипа.

1

Как отметил Оли Чарльворт, виртуальные указатели являются деталями реализации, поэтому этот вопрос на самом деле не имеет смысла с точки зрения C++. Тем не менее, следующее руководство по реализации (некоторые функции) виртуальных функций может быть полезной для понимания:

struct vtable { 
    void (*display)(void*); 
    void (*setValue)(void*, int); 
}; 

void A_display(void *this_) { /*Cast this_ to A* and do A stuff*/ } 
void A_setValue(void *this_, int x) { /*Cast this_ to A* and do A stuff*/ } 

vtable A_vtable = {A_display, A_setValue}; 

struct A { 
    vtable *vptr = &A_vtable; 
    int a; 
    public: A(){} 
}; 

void B_display(void *this_) { /*Cast this_ to B* and do B stuff*/ } 
void B_setValue(void *this_, int x) { /*Cast this_ to B* and do B stuff*/ } 

vtable B_vtable = {B_display, B_setValue}; 

struct B { 
    vtable *vptr = &B_vtable; 
    int a; 
    public: B(){} 
}; 

void display(void *obj) { 
    ((*static_cast<vtable**>(obj))->display)(obj); 
} 
void setValue(void *obj, int) { 
    ((*static_cast<vtable**>(obj))->setValue)(obj, int); 
} 

Конечно, это только дает небольшое подмножество возможностей виртуальных функций, но она должна достаточно просто видеть, что vptrs указывают на коллекции указателей на функции с фиксированными типами.

1

Виртуальная таблица (в реализациях, использующих такую ​​вещь) является продуктом «магии компилятора». Он не должен иметь определенный прототип, потому что ни один C++-код никогда не использует его напрямую. Вместо этого компилятор настраивает, чтобы он соответствовал каждому классу, который ему нужен. Компилятор также генерирует код для доступа к каждому элементу, поэтому он может гарантировать доступ к каждому из них безопасным образом.

Например, компилятор знает, что слот для метода A::setValue содержит указатель на функцию, которая соответствует подписи setValue, потому что компилятор - это тот, который помещает ее туда в первую очередь. Кроме того, единственным кодом, который напрямую обращается к этому слоту, является машинный код, сгенерированный компилятором, и до создания такого кода компилятор уже подтвердил, что исходный код на C++ вызывал функцию setValue. Таким образом, нет никаких сомнений в том, что слот setValue мог бы удерживать что-либо, кроме указателя функции setValue. Также не вызывает беспокойства, что к другому слоту можно было бы обратиться; если это произойдет, это будет ошибка компилятора, никогда не произойдет что-то, что произойдет в результате обычного кода пользователя.

Элементы таблицы никогда не рассматриваются как группа, поэтому нет требования, чтобы все они имели один и тот же тип. В лучшем случае все они имеют тип «общего указателя или смещения, подходящего для перехода к CPU». Поскольку на данный момент это не C++, «тип» не должен соответствовать какому-либо конкретному типу C++.

 Смежные вопросы

  • Нет связанных вопросов^_^