2011-11-22 81 views
1

vtable是当基类具有虚函数时,所有基类/派生类中的开销。 vtable应该包含一个函数指针数组,这些函数指针用于这些virtual函数。 vtable是“每个类一个”,而不是“每个对象一个”。运行时虚拟函数调用(std C++)

现在想象一下创建这样一个类的对象。它将在运行时在某个内存位置获得类的新功能virtual。由于vtable是函数指针的集合,它将被更新以反映这一点。如果创建同一类的其他对象,然后它会再次拥有的virtual功能的全新副本,在其他一些存储位置

由于虚函数表是“每类一个”而不是“每个实例一个”怎么会呢指向不同实例的正确位置?

回答

8

这很简单... vftable本身是one-per-class,指针是one-per-instance。两个相同类型的实例的vftable指针指向同一个位置。

class A 
{ 
    virtual void foo(); 
    virtual void goo(); 
} 

class B : public A 
{ 
    virtual void foo(); 
} 

在内存中,你将有:

vftable for A: 

+----------+---------+ 
| 0x01 | 0x02 | 
+----------+---------+ 
    &A::foo() &A::goo() 

vftable for B: 

+----------+---------+ 
| 0x11 | 0x12 | 
+----------+---------+ 
    &B::foo() &A::goo() 

假设您创建两个对象:

A a; 
B b; 

A的第一个成员是:

vftableptr: 0x01 

B的第一个成员将是

vftableptr: 0x11 

一般而言,已实现多态得到vftable的地址,添加函数偏移(例如,如果我们称之为goo(),偏移量是1),和跳跃到该位置。由于对象类型不同,它们将指向不同的位置,但vftables(不同)可以包含类似的成员。

重要提示:值是假的,偏移量不是1也不是地址0x01等,我选择他们来说明问题。

+0

评论,如果你从一个类层次结构有有一个类的单个实例是没有问题的。我想知道的是,如果为上述代码执行两次“new B”,则会在内存中分别存储“foo()”的副本,但只有一个vtable.virtual指针指向vtable的条目(每个类只有一个)..那么如何解决单独实例的虚函数调用? – ustulation

+0

+1对于一个很好的解释。 @ustulation:在此背景下展开您的问题。B的所有实例都有一个指向位置'0x11'的vtable,但是B的每个函数标识B的不同实例的方式是从所有成员函数的第一个“不可见”参数开始的,它是实例本身的指针,我们在函数中将this引用为this,或者在不使用this的情况下引用成员变量或函数时隐式推断。 –

+1

oh..ok ..所以基本上我的理解,会有多个副本“foo()”不正确..因为马克B似乎也说...“foo()”总是在相同的地方,但其中的操作(关于成员变量,传递参数或局部变量)将获得不同的副本,并将由“this”指针解决...我是否关闭? – ustulation

3

在使用vtables的实现中,每个多态对象都有一个指针到它的类vtable。

+0

多数民众赞成true..but一类口岸为一类相同的虚函数表的一个实例的每个虚拟指针......请阅读我给Luchian的回答 – ustulation

5

对于类的每个实例都没有单独的函数,所以vtable始终指向相同的函数。每个类实例都有一个指向vtable的指针。