c++ - 虚函数和vtable是如何实现的?

标签 c++ polymorphism virtual-functions vtable

我们都知道 C++ 中的虚函数是什么,但它们是如何深入实现的呢?

可以在运行时修改甚至直接访问vtable吗?

vtable 是否适用于所有类,还是仅适用于至少具有一个虚函数的类?

抽象类是否只是简单地为至少一个条目的函数指针设置了一个 NULL 值?

只有一个虚函数会减慢整个类(class)的速度吗?还是只调用虚拟函数?如果虚函数实际上被覆盖,速度是否会受到影响,或者只要它是虚函数就没有影响。

最佳答案

虚函数是如何深层次实现的?

来自 "Virtual Functions in C++" :

Whenever a program has a virtual function declared, a v - table is constructed for the class. The v-table consists of addresses to the virtual functions for classes that contain one or more virtual functions. The object of the class containing the virtual function contains a virtual pointer that points to the base address of the virtual table in memory. Whenever there is a virtual function call, the v-table is used to resolve to the function address. An object of the class that contains one or more virtual functions contains a virtual pointer called the vptr at the very beginning of the object in the memory. Hence the size of the object in this case increases by the size of the pointer. This vptr contains the base address of the virtual table in memory. Note that virtual tables are class specific, i.e., there is only one virtual table for a class irrespective of the number of virtual functions it contains. This virtual table in turn contains the base addresses of one or more virtual functions of the class. At the time when a virtual function is called on an object, the vptr of that object provides the base address of the virtual table for that class in memory. This table is used to resolve the function call as it contains the addresses of all the virtual functions of that class. This is how dynamic binding is resolved during a virtual function call.

可以在运行时修改甚至直接访问vtable吗?

总的来说,我相信答案是“不”。你可以做一些内存修改来找到 vtable,但你仍然不知道函数签名是什么样子的。您想通过这种能力(语言支持)实现的任何事情都应该可以在不直接访问 vtable 或在运行时修改它的情况下实现。另请注意,C++ 语言规范没有指定 vtable 是必需的 - 但是大多数编译器都是这样实现虚函数的。

vtable 是否存在于所有对象,还是只存在于具有至少一个虚函数的对象?

相信这里的答案是“这取决于实现”,因为规范首先不需要 vtables。然而,在实践中,我相信所有现代编译器只有在一个类至少有 1 个虚函数时才会创建一个 vtable。存在与 vtable 相关的空间开销以及与调用虚函数与​​非虚函数相关的时间开销。

抽象类是否简单地为至少一个条目的函数指针设置了一个 NULL?

答案是语言规范未指定它,因此它取决于实现。如果未定义(通常未定义),则调用纯虚函数会导致未定义的行为(ISO/IEC 14882:2003 10.4-2)。实际上,它确实在 vtable 中为函数分配了一个槽,但没有为其分配地址。这使得 vtable 不完整,需要派生类来实现功能并完成 vtable。一些实现只是在 vtable 条目中放置一个 NULL 指针;其他实现会放置一个指向虚拟方法的指针,该方法执行类似于断言的操作。

请注意,抽象类可以定义纯虚函数的实现,但该函数只能使用限定 ID 语法调用(即,在方法名称中完全指定类,类似于调用基类派生类的方法)。这样做是为了提供易于使用的默认实现,同时仍需要派生类提供覆盖。

只有一个虚函数会减慢整个类的速度还是只减慢对虚函数的调用?

这是我知识的边缘,所以如果我错了,请有人帮助我!

相信只有类中的虚函数会经历与调用虚函数与​​非虚函数相关的时间性能损失。无论哪种方式,类(class)的空间开销都是存在的。请注意,如果有 vtable,则每个 class 只有 1 个,而不是每个 object 一个。

如果虚函数实际上被覆盖,速度是否会受到影响,或者只要它是虚函数就没有影响?

我不相信与调用基本虚函数相比,被覆盖的虚函数的执行时间不会减少。但是,与为派生类和基类定义另一个 vtable 相关联的类会产生额外的空间开销。

其他资源:

http://www.codersource.net/published/view/325/virtual_functions_in.aspx (通过返程机)
http://en.wikipedia.org/wiki/Virtual_table
http://www.codesourcery.com/public/cxx-abi/abi.html#vtable

关于c++ - 虚函数和vtable是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/99297/

相关文章:

c++ - SCons:如何让库获取 CPPPATH 选项

c++ - C++11 auto 关键字太多了?

java - Java中如何正确使用多态调用正确类的方法

c++ - 使用非虚拟接口(interface)习惯用法,我的非虚拟函数可以/将被内联吗?

c++ - 类层次结构中 dynamic_cast 的替代方法

c++ - 多线程错误

c++ - 函数调用重置传递的全局结构的字段

c# - 泛型类型参数中的多态性

java - 无法访问数组java中的对象

c++ - 非重写虚函数的绑定(bind)类型