первый:
Я где-то читал, что механизм виртуальных функций не определен. это означает, что каждый компилятор может реализовать его по-своему. Но каждый текст, который я нашел о механизме виртуальных функций, говорит о VTBL и VPTR.
Существуют ли другие реализации механизма виртуальных функций? Не могли бы вы привести несколько примеров?
второй:
В чем различия между реализацией VTBL на разных языках?
Одна популярная альтернатива встроенное кэширование это, я думаю, происходит из систем Smalltalk.
Другой альтернативой является наличие таблицы типов для каждого полиморфного метода вместо использования таблицы полиморфного метода (VMT) для каждого типа. Это требует анализа всей программы, но делает возможным эффективное множественное наследование. Некоторые компиляторы Eiffel используют такой метод (больше здесь, ищите «Как эффективно реализовать множественное наследование?»).
В последнем также упоминается другой метод — подход, основанный на выражении switch (просмотрите в Eiffel ~ switch в C). SmartEiffel использует его вариант, он выполняет бинарный поиск по идентификатору класса. Это также требует анализа всей программы, но иногда может быть более эффективным, чем VMT в современных системах благодаря лучшему поведению кэша команд. (больше здесь, ищите «Эффективная динамическая диспетчеризация без таблиц виртуальных функций»).
Я покажу вам пример.
class B
{
private:
int m_i;
public:
void foo() { puts("B::foo"); }
virtual void bar() { puts("B::bar"); }
};
class D : public B
{
private:
int m_j;
public:
virtual void bar() { puts("D::bar"); }
virtual void asdf() { puts("D::asdf"); }
};
int main()
{
D d;
B *pb = &d;
pb->bar();
}
Большинство компиляторов реализуют этот код следующим образом:
struct B;
struct __vtbl_B_t
{
void (*bar)(B * const this);
};
struct B
{
const __vtbl_B_t *__vptr;
int m_i;
};
void B__foo(B * const this) { puts("B::foo"); }
void B__bar(B * const this) { puts("B::bar"); }
const __vtbl_B_t __vtbl_B = { B__bar };
void B__ctor(B * const this)
{
this->__vptr = &__vtbl_B;
}
struct D;
struct __vtbl_D_t
{
__vtbl_B_t __base;
void (*asdf)(D * const this);
};
struct D
{
B __base;
int m_j;
};
void D__bar(D * const this) { puts("D::bar"); }
void D__asdf(D * const this) { puts("D::asdf"); }
__vtbl_D_t __vtbl_D = { { (void (*)(B * const))D__bar }, D__asdf };
void D__ctor(D * const this)
{
B__ctor((B * const)this);
this->__base.__vptr = (const __vtbl_B_t *)&__vtbl_D;
}
int main()
{
D d;
D__ctor(&d);
B *pb = (B *)&d;
(*pb->__vptr->bar)(pb);
}
Выход:
D::bar
Даже если ваш язык не является C ++, поведение компиляторов похоже.
Это может помочь вам:
Таблица виртуальных методов: сравнение с альтернативами
Различные поставщики компиляторов могут выбрать другой метод … Но конечная реализация должна соответствовать стандарту. что это …
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf (раздел 10.3)