我遇到过文章,他们解释了vptr和vtable。我知道在存储虚函数的类的情况下,对象中的第一个指针是vptr到vtable,而vtable的数组条目是指向函数的指针,它们在类中出现的顺序相同(我已经通过我的测试验证了)程序)。但我试图理解必须编译器放置什么语法才能调用适当的函数。
例:
class Base
{
virtual void func1()
{
cout << "Called me" << endl;
}
};
int main()
{
Base obj;
Base *ptr;
ptr=&obj;
// void* is not needed. func1 can be accessed directly with obj or ptr using vptr/vtable
void* ptrVoid=ptr;
// I can call the first virtual function in the following way:
void (*firstfunc)()=(void (*)(void))(*(int*)*(int*)ptrVoid);
firstfunc();
}
问题:
但我真正想要了解的是编译器如何用ptr->func1()
替换对vptr
的调用?如果我要模拟电话,那我该怎么办?我应该重载->
运算符。但即便如此也无济于事,因为我不知道func1
的名字到底是什么。即使他们说编译器通过vptr访问vtable,它仍然知道func1
的条目是func2
的第一个数组adn条目是数组中的第二个元素吗?必须将函数名称映射到数组元素。
2.我该如何模拟它。你能提供编译器用来调用函数func1
的实际语法(它如何取代ptr->func1()
)?
不要将vtable视为数组。它只是一个数组,如果你除去它的成员大小以外的C ++所知道的一切。相反,把它想象成第二个struct
,其成员都是功能的指针。
假设我有一个这样的类:
struct Foo {
virtual void bar();
virtual int baz(int qux);
int quz;
}
int callSomeFun(Foo* foo) {
foo->bar();
return foo->baz(2);
}
分解一步:
class Foo;
// adding Foo* parameter to simulate the this pointer, which
// in the above would be a pointer to foo.
struct FooVtable {
void (*bar)(Foo* foo);
int (*baz)(Foo* foo, int qux);
}
struct Foo {
FooVtable* vptr;
int quz;
}
int callSomeFun(Foo* foo) {
foo->vptr->bar(foo);
return foo->vptr->baz(foo, 2);
}
我希望这就是你要找的东西。
的背景:
它唯一的形象。实施必须正确触发覆盖classApionter->methodReimplementedInB()
sizeof()
非常好理解(数据大小加上ev。对齐),在C ++中sizeof更大,但可以保证它是2,4,8字节。4很少有转换工具可以转换“对象”文件,即从MS格式转换为Borland等,但由于vtable的未知机器代码实现,通常/只有经典C是可能的/安全的。
编辑:关于运行时的故事与编译不同。我的答案是关于编译代码和运行时
EDIT2:准汇编代码(来自我的脑海)
load ax, 2
call vt[ax]
vt:
0x123456
0x126785 // virlual parent func1()
衍生:
vt:
0x123456
0x126999 // overriden finc1()
0x456788 // new method
编辑3:BTW我不能完全同意C ++总是更好地加速JVM / .NET,因为“这些被解释”。 C ++有“intepretation”的一部分,解释部分是groving:真正的组件/ GUI框架也解释了之间的连接(例如map)。在我们的讨论中:使用C ++ delete还是GC,哪种内存模型更好?