首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么抽象类有vtable?

为什么抽象类有vtable?
EN

Stack Overflow用户
提问于 2016-09-08 10:58:05
回答 3查看 1.6K关注 0票数 6

关于帖子:

对于使用vtable的实现,答案是:是的,通常。您可能认为抽象类不需要vtable,因为派生类将有自己的vtable,,但是在构造过程中需要它:在构建基类时,它会将 vtable指针设置为自己的vtable。稍后,当输入派生类构造函数时,它将使用自己的vtable代替.

我假设答案是正确的,但我不太明白。为什么要建造vtable呢?

EN

回答 3

Stack Overflow用户

发布于 2016-09-08 11:29:20

因为标准是这么说的。

[class.cdtor]/4

当一个虚拟函数直接或间接地从构造函数或析构函数调用时,包括在构造或销毁类的非静态数据成员期间,而该调用应用到的对象是正在构造或销毁的对象(称为x),则调用的函数是构造函数或析构函数类中的最终覆盖器,而不是在更派生的类中重写它的函数。

其基本原理是,首先构造基类,然后构造派生类。如果在基类构造函数中调用虚拟函数,则调用派生类将是错误的,因为派生类尚未初始化。

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

如果所有的虚拟函数都是纯的,那么在MSVC中,可以使用__declspec(novtable)省略vtable。如果您使用了大量的接口类,这可能会节省大量费用,因为您忽略了vfptr初始化。但是,如果您意外地调用了一个纯虚拟函数,您将很难调试访问冲突。

票数 3
EN

Stack Overflow用户

发布于 2016-09-08 13:26:46

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

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

C++实现和ABI的设计者可能只是给纯粹的抽象类(一个没有实现方法的类,只有=0方法)一个vtable来简化它们的实现。每个类都有一个vtable,并且vtable指针在该类的构造过程中被设置。然后,代码可以依赖于这样一个事实,即vtable指针存在,并且不必每次都检查null。代码不需要问“这是一个纯粹的抽象类”这样的问题。

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

票数 0
EN

Stack Overflow用户

发布于 2016-09-08 11:17:57

当您的类具有纯虚拟函数时,这并不意味着您也不能为其提供一个实现(!!)。这意味着您可以有一个抽象类,这个类也是完全实现的。抽象类的构造函数必须能够调用到目前为止存在的所有函数--甚至是纯虚拟函数。

如果您已经替换了客户端构造器,则会根据派生类得到不同的基类构造函数的行为--这不是一个好主意,所以这是不允许的。您可以不设置vtable并静态解析所有函数调用--这是可行的,但它意味着处理构造函数(与所有其他函数相比),并且需要内联所有其他函数来完成这一任务(因为从构造函数调用的函数也可能调用虚拟函数等等)--不太实用。

因此,它只是为构造函数和析构函数实现了一个vtable,以便在构造和销毁过程中使用。它允许您在c‘to和d’to中使用typeid和dynamic_cast,得到可预测的结果,并从所拥有的虚拟函数中获得可靠的行为。没有其他解决办法可以做到这一点。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39389157

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档