接口(仅具有纯虚函数的多态类)是否具有vtable? 由于接口本身不实现多态函数并且不能直接构造,因此链接器不需要放置vtable。是这样吗?我特别关注MSVC编译器。
答案 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。这并不是特别难,但仍然远非微不足道。由于它在常规代码中没有提供真正的速度优势,因此我所知道的任何编译器都没有实现检查。