为什么抽象类有vtable?

时间:2016-09-08 10:58:05

标签: c++ constructor abstract-class vtable pure-virtual

关于this帖子:

  

对于使用vtable的实现,答案是:通常是。您   可能认为抽象类不需要vtable,因为   派生类将有自己的vtable,但在期间需要它   构造:在构建基类时,它设置    vtable指向自己的vtable的指针。后来派生类   输入构造函数,它将使用自己的vtable。

我假设答案是正确的,但我不太明白。为什么vtable需要完全用于施工?

3 个答案:

答案 0 :(得分:3)

因为标准是这样说的。

[class.cdtor]/4

  

直接或间接从a调用虚函数时   构造函数或析构函数,包括在构造期间或   破坏类的非静态数据成员,以及对象   调用适用的是正在构建的对象(称为x)或   破坏,所谓的函数是最终的覆盖者   构造函数或析构函数的类,而不是一个覆盖它的类   更多派生的类。

基本原理是首先构建基类,然后派生的基类。如果在基类内调用虚函数'构造函数,调用派生类是不好的,因为派生类尚未初始化。

请记住,抽象类可能具有非纯虚函数。此外,出于调试目的,最好将纯虚函数指向调试陷阱(例如,MSVC调用_purecall())。

如果所有虚拟功能都是纯粹的,那么在MSVC中,您可以使用__declspec(novtable)省略vtable。如果使用大量接口类,这可以节省大量成本,因为省略了vfptr初始化。但是,如果您不小心调用了纯虚函数,那么您将很难调试访问冲突。

答案 1 :(得分:0)

vtables是C ++中的实现问题,它们不是标准的一部分。

vtable用于动态调度方法和RTTI。虽然nullptr vtable指针可用于动态分派(因为vtable指针仅在具有该类型的实例时使用)在纯抽象类中,但dynamic_cast到纯抽象类是合法的,并且它可能要求vtable本身存在。

C ++实现和ABI的设计者可能只是简单地给出了纯抽象类(没有实现方法的类,只有=0个)vtable,以使其实现更简单。每个类都有一个vtable,并且在构造该类时会设置vtable指针。然后,代码可以依赖于vtable指针存在的事实,并且不必每次都检查null。代码不必提出像#34这样的问题;这是一个纯粹的抽象类"。

对于非纯抽象类(其中某些方法具有实现但有些方法是纯虚拟的),在构造/销毁期间,您可以定义(如果是意外的)行为,该行为涉及完全调用此类的给定版本方法,而不是基类方法或继承方法。为此,您需要设置vtable。对于纯抽象类,没有这种调用的定义结果,因此vtable是多余的,但是对于一个不完全抽象的抽象类,这是不成立的。

答案 2 :(得分:-1)

当你的类具有纯虚函数时,这并不意味着你也不能拥有它的实现(!!)。这意味着你可以拥有一个抽象类,它也是完全实现的。抽象类的构造函数必须能够调用所有函数 - 即使是纯虚函数 - 因为这一点 - 到目前为止它仍然存在。

如果您已经替换了客户端,那么根据派生类,您将获得基类构造函数的不同行为 - 这不是一个好主意,因此不允许这样做。您可以放置​​没有vtable并静态解析所有函数调用 - 这是有效的,但它意味着处理构造函数与所有其他函数相比,并且需要内联所有其他函数来执行此操作(因为从构造函数调用的函数也可能调用虚拟等) - 不太实用。

因此它只是为构造函数和析构函数实现了一个vtable,以便在构造和销毁期间使用它。它允许您在c'tor和d'tor中使用typeid和dynamic_cast以及可预测的结果,并从您拥有的虚拟函数中获得可靠的行为。没有替代解决方案可以做到这一点。