vtable - это массив указателей на функции.В контексте одного наследования у вас будет один такой массив на класс, где элементы массива являются виртуальными методами класса.Каждый объект будет содержать указатель на vtable своего класса, и каждый вызов виртуального метода будет просто вызывать соответствующий указатель в vtable (после приведения его к нужному типу).
Итак, допустим, вы компилируете программуэто выглядит так:
class A {
int x,y;
virtual int foo() { return x+y; }
virtual int bar() { return x*y; }
}
class B inherits A {
int z;
override int bar() { return x*y+z; }
}
int f(A a) {
return a.foo() + a.bar();
}
Тогда вы можете определить функции с именами A_foo
, A_bar
и B_bar
, взяв указатель A
или B
и содержащий код для A.foo
,A.bar
и B.bar
соответственно (точное название будет, конечно, зависеть от вашей схемы искажения имени).Затем вы сгенерируете два глобальных значения A_vtable
и B_vtable
, которые будут выглядеть следующим образом:
@A_vtable = global [2 x void (...)*] [
void (...)* bitcast (i32 (%struct.A*)* @A_foo to void (...)*),
void (...)* bitcast (i32 (%struct.A*)* @A_bar to void (...)*)
]
@B_vtable = global [2 x void (...)*] [
void (...)* bitcast (i32 (%struct.A*)* @A_foo to void (...)*),
void (...)* bitcast (i32 (%struct.B*)* @B_bar to void (...)*)
]
, которые будут соответствовать этому коду C (который, мы надеемся, более читабелен):
typedef void (*fpointer_t)();
fpointer_t A_vtable[] = {(fpointer_t) A_foo, (fpointer_t) A_bar};
fpointer_t B_vtable[] = {(fpointer_t) A_foo, (fpointer_t) B_bar};
f
можно затем перевести так:
define i32 @f(%struct.A*) {
%2 = getelementptr inbounds %struct.A, %struct.A* %0, i64 0, i32 0
%3 = bitcast %struct.A* %0 to i32 (%struct.A*)***
%4 = load i32 (%struct.A*)**, i32 (%struct.A*)*** %3
%5 = load i32 (%struct.A*)*, i32 (%struct.A*)** %4
%6 = call i32 %5(%struct.A* %0)
%7 = load void (...)**, void (...)*** %2
%8 = getelementptr inbounds void (...)*, void (...)** %7, i64 1
%9 = bitcast void (...)** %8 to i32 (%struct.A*)**
%10 = load i32 (%struct.A*)*, i32 (%struct.A*)** %9
%11 = call i32 %10(%struct.A* %0)
%12 = add nsw i32 %11, %6
ret i32 %12
}
Или в C:
typedef int (*A_int_method_t)(struct A*);
int f(struct A* a) {
return ((A_int_method_t) a->vtable[0])(a) + ((A_int_method_t) a->vtable[1])(a);
}