假设我们有类似 Java 语言的接口:
interface Animal {
public int getAge();
}
interface Tamable {
public void tame();
}
那些接口是由类实现的:
class Cat implements Animal { // Cats are not tamable
public int getAge() { // this method is somewhere in memory (e.g. at 0xf000)
// ...
}
}
class Dog implements Animal, Tamable {
public int getAge() { // this method is somewhere in memory (e.g. at 0xf008)
// ...
}
public void tame() { // this method is somewhere in memory (e.g. at 0xf00e)
// ...
}
}
将接口
Tamable
传递给其他方法时,如下所示:
void pet(Tamable tamable) {
tamable.tame(); // <-- this call
// ...
}
我们怎么知道调用
tame()
时要跳转到哪个内存地址? VMT(Virtual Method Table)在这种情况下是如何实现的?
我能想象它们被实现的唯一方法是一些哈希表,但这似乎会使虚拟调度非常慢。
如果 VMT 只是函数指针的数组/向量,那么编译器如何知道在类
tame()
上使用什么偏移量来获取函数指针 Dog
,在调度调用时,在编译时它无法在任何时候解析 tamable
会是 Dog
还是 Cat
?
(注意:Java 只是作为示例使用,我正在寻找更通用的答案)
任何建议都会有所帮助。我在互联网上找到的所有资源都非常模糊地描述了如何实现 VMT 以及如何获得 VMT 的密钥。
对于每个实现的接口,类的对象包含指向该接口的 VMT 的指针(所谓的
vptr
)。每当你调用一个将接口作为参数的函数时(比如你的情况下的pet
),这个指针就会在幕后传递。
每个 VMT 只是一个函数指针数组。表中每个方法的索引由编译器根据接口声明中方法的顺序静态分配。