界面vtable

时间:2012-06-25 19:51:14

标签: c++ interface polymorphism vtable

接口(仅具有纯虚函数的多态类)是否具有vtable? 由于接口本身不实现多态函数并且不能直接构造,因此链接器不需要放置vtable。是这样吗?我特别关注MSVC编译器。

3 个答案:

答案 0 :(得分:8)

是的,他们这样做。并且有很多充分的理由。

第一个很好的理由是即使是纯虚方法也有实现。隐式或显式。调用纯虚函数的技巧相对容易,所以你基本上可以为你的一个提供一个定义,调用它,看看会发生什么。出于这个原因,首先应该有一个虚拟表。

将虚拟表放入基类有另一个原因,即使它的所有方法都是纯虚拟的,但是没有其他数据成员。使用多态时,会在程序周围传递指向基类的指针。为了调用虚方法,编译器/运行时应该计算出虚拟表与基指针的相对偏移量。如果C ++没有多重继承,那么可以假定从抽象基类零偏移(例如),在这种情况下,那里可能没有vtable(但由于理由#1,我们仍然需要它)。但是由于涉及多重继承,因此根据基类的数量(和类型),可能有两个或三个vtable,但是技巧ala“vtable在0偏移处”将无效。

我可能还有其他原因。

希望它有所帮助。

答案 1 :(得分:5)

从纯粹的C ++角度来看,这是一个学术问题。虚拟函数不必用vtable实现,如果它们没有可移植的方式来获取它们。

如果您特别关注MSVC编译器,可能需要使用__declspec(novtable)来修饰接口。

(通常,在通常的实现中,抽象类可能需要vtable,例如:

struct Base {
    Base();
    virtual void f() {}
    virtual void g() = 0;
};

void h(Base& b) {
    b.f(); // Call f on a Base that is not (yet) a Derived
           // vtable for Base required
}

Base::Base() {
    h(*this);
}

struct Derived : Base {
    void g() {}
};

int main() {
    Derived d;
}

答案 2 :(得分:1)

vtable不是必需的,但很少进行优化。 MSVC提供__declspec(novtable)扩展,它明确告诉编译器可以删除vtable。如果没有,编译器必须检查自己是否使用了vtable。这并不是特别难,但仍然远非微不足道。由于它在常规代码中没有提供真正的速度优势,因此我所知道的任何编译器都没有实现检查。