How are virtual functions and vtable implemented?(虚函数和vtable是如何实现的?)
问题描述
我们都知道 C++ 中的虚函数是什么,但它们是如何深入实现的呢?
We all know what virtual functions are in C++, but how are they implemented at a deep level?
可以在运行时修改甚至直接访问vtable吗?
Can the vtable be modified or even directly accessed at runtime?
vtable 是否适用于所有类,还是仅适用于至少具有一个虚函数的类?
Does the vtable exist for all classes, or only those that have at least one virtual function?
抽象类是否只是简单地为至少一个条目的函数指针设置了一个 NULL 值?
Do abstract classes simply have a NULL for the function pointer of at least one entry?
只有一个虚函数会减慢整个班级的速度吗?还是只调用虚拟函数?如果虚函数实际上被覆盖,速度是否会受到影响,或者只要它是虚函数就没有影响.
Does having a single virtual function slow down the whole class? Or only the call to the function that is virtual? And does the speed get affected if the virtual function is actually overwritten or not, or does this have no effect so long as it is virtual.
推荐答案
虚函数是如何深层次实现的?
来自 "C++ 中的虚函数":
只要程序声明了一个虚函数,就会为该类构造一个 v - 表.v-table 由包含一个或多个虚函数的类的虚函数地址组成.包含虚函数的类的对象包含一个虚指针,它指向内存中虚表的基地址.每当有虚函数调用时,都会使用 v-table 解析到函数地址.包含一个或多个虚拟函数的类的对象在内存中对象的最开始包含一个称为 vptr 的虚拟指针.因此,在这种情况下,对象的大小会增加指针的大小.这个 vptr 包含内存中虚拟表的基地址.请注意,虚拟表是特定于类的,即一个类只有一个虚拟表,而与它包含的虚拟函数的数量无关.该虚拟表又包含该类的一个或多个虚拟函数的基地址.在对象上调用虚函数时,该对象的 vptr 提供了该类在内存中的虚拟表的基地址.该表用于解析函数调用,因为它包含该类的所有虚函数的地址.这就是在虚函数调用期间解决动态绑定的方式.
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 是必需的 - 但是大多数编译器都是这样实现虚函数的.
Can the vtable be modified or even directly accessed at runtime?
Universally, I believe the answer is "no". You could do some memory mangling to find the vtable but you still wouldn't know what the function signature looks like to call it. Anything that you would want to achieve with this ability (that the language supports) should be possible without access to the vtable directly or modifying it at runtime. Also note, the C++ language spec does not specify that vtables are required - however that is how most compilers implement virtual functions.
我相信这里的答案是这取决于实现",因为规范首先不需要 vtables.然而,在实践中,我相信所有现代编译器只有在一个类至少有 1 个虚函数时才会创建一个 vtable.存在与 vtable 相关的空间开销以及与调用虚函数与非虚函数相关的时间开销.
I believe the answer here is "it depends on the implementation" since the spec doesn't require vtables in the first place. However, in practice, I believe all modern compilers only create a vtable if a class has at least 1 virtual function. There is a space overhead associated with the vtable and a time overhead associated with calling a virtual function vs a non-virtual function.
答案是语言规范未指定它,因此它取决于实现.如果未定义(通常未定义),则调用纯虚函数会导致未定义的行为(ISO/IEC 14882:2003 10.4-2).实际上,它确实在 vtable 中为函数分配了一个槽,但没有为其分配地址.这使得 vtable 不完整,需要派生类来实现功能并完成 vtable.一些实现只是在 vtable 条目中放置一个 NULL 指针;其他实现会放置一个指向虚拟方法的指针,该方法执行类似于断言的操作.
The answer is it is unspecified by the language spec so it depends on the implementation. Calling the pure virtual function results in undefined behavior if it is not defined (which it usually isn't) (ISO/IEC 14882:2003 10.4-2). In practice it does allocate a slot in the vtable for the function but does not assign an address to it. This leaves the vtable incomplete which requires the derived classes to implement the function and complete the vtable. Some implementations do simply place a NULL pointer in the vtable entry; other implementations place a pointer to a dummy method that does something similar to an assertion.
请注意,抽象类可以定义纯虚函数的实现,但该函数只能使用限定 ID 语法调用(即,在方法名称中完全指定类,类似于调用基类派生类的方法).这样做是为了提供易于使用的默认实现,同时仍需要派生类提供覆盖.
Note that an abstract class can define an implementation for a pure virtual function, but that function can only be called with a qualified-id syntax (ie., fully specifying the class in the method name, similar to calling a base class method from a derived class). This is done to provide an easy to use default implementation, while still requiring that a derived class provide an override.
这是我知识的边缘,所以如果我错了,请有人帮助我!
This is getting to the edge of my knowledge, so someone please help me out here if I'm wrong!
我相信只有类中的虚函数会经历与调用虚函数与非虚函数相关的时间性能损失.无论哪种方式,课程的空间开销都是存在的.请注意,如果有 vtable,则每个 class 只有 1 个,而不是每个 object 一个.
I believe that only the functions that are virtual in the class experience the time performance hit related to calling a virtual function vs. a non-virtual function. The space overhead for the class is there either way. Note that if there is a vtable, there is only 1 per class, not one per object.
我不相信与调用基本虚函数相比,被覆盖的虚函数的执行时间不会减少.但是,与为派生类和基类定义另一个 vtable 相关联的类会产生额外的空间开销.
I don't believe the execution time of a virtual function that is overridden decreases compared to calling the base virtual function. However, there is an additional space overhead for the class associated with defining another vtable for the derived class vs the base class.
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
这篇关于虚函数和vtable是如何实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:虚函数和vtable是如何实现的?
- C++浮点常数 1970-01-01
- C语言可使用的所有转义序列 1970-01-01
- 打印扩展的ASCII字符 1970-01-01
- 使用来自float.h和limits的数据,找到该系统的一些 1970-01-01
- C++指向数组的指针 1970-01-01
- 运算符优先级 1970-01-01
- “纯虚函数调用"在哪里?崩溃从何而来? 2022-10-18
- C语言求模 1970-01-01
- 使用整数值初始化char类型的变量 1970-01-01
- 使用最流行的转义序列 1970-01-01