问题标签 [vtable]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
0 回答
327 浏览

virtual-functions - 返回 std::string 的虚函数没有“add esp,4”

我一直在研究DynObj并决定用 vftables 做我自己的实验。我正在使用 Visual Studio 2010 并创建了一个控制台主程序,它使用一个返回 std::string 的虚拟函数来实例化一个对象。

main 中的测试代码尝试使用从对象的 vftable 获得的指针调用对象的公共虚函数。我发现对于返回原始类型的函数没有问题。但是当函数返回一个 std::string 时,编译器会插入一个有效的堆栈弹出(添加 esp,4)。这会导致随后的堆栈检查代码引发异常。

我注意到这是在全局空间中声明的函数的规范。但是类中的函数不会在调用后生成 ESP 修饰符。

这是代码的本质以及程序集......

通过强制转换的指针对虚函数的最后一次调用导致:

运行时检查失败 #0 - ESP 的值未在函数调用中正确保存。这通常是调用使用一种调用约定声明的函数和使用另一种调用约定声明的函数指针的结果。

所以我的问题是:如何在返回非原始类型的虚函数上调用正确的调用约定?

顺便说一句,当我在 00BE178B 中断并将下一条语句设置为 00BE178E 时,执行完成没有问题。

0 投票
4 回答
1698 浏览

c++ - 使用虚拟析构函数会使非虚拟函数进行 v-table 查找吗?

正是主题所要求的。还想知道为什么 CRTP 的常见示例中没有提到virtualdtor。

编辑:伙计们,请也发布有关 CRTP 问题的信息,谢谢。

0 投票
3 回答
10019 浏览

c++ - 虚拟调度实现细节

首先,我想明确表示我确实理解 C++ 标准中没有 vtables 和 vptrs 的概念。但是我认为几乎所有实现都以几乎相同的方式实现虚拟调度机制(如果我错了,请纠正我,但这不是主要问题)。另外,我相信我知道虚函数是如何工作的,也就是说,我总能知道哪个函数会被调用,我只需要实现细节。

假设有人问我以下问题:
“您有带有虚函数 v1、v2、v3 的基类 B 和派生类 D:B,它覆盖了函数 v1 和 v3 并添加了一个虚函数 v4。解释虚拟调度的工作原理”。

我会这样回答:
对于每个具有虚函数的类(在本例中为 B 和 D),我们都有一个单独的指向函数的指针数组,称为 vtable。
B 的 vtable 将包含

D 的 vtable 将包含

现在类 B 包含一个成员指针 vptr。D 自然地继承了它,因此也包含它。在 BB 的构造函数和析构函数中设置 vptr 指向 B 的 vtable。在DD的构​​造函数和析构函数中设置它指向D的vtable。
任何对多态类 X 的对象 x 的虚函数 f 的调用都被解释为对 x.vptr[f 在 vtables 中的位置] 的调用

问题是:
1. 我上面的描述有什么错误吗?
2. 编译器如何知道 f 在 vtable 中的位置(请详细说明)
3. 这是否意味着如果一个类有两个基数,那么它就有两个 vptr?在这种情况下发生了什么?(尝试以与我类似的方式描述,尽可能详细地描述)
4. A 在顶部 B,C 在中间,D 在底部的菱形层次结构中发生了什么?(A 是 B 和 C 的虚拟基类)

提前致谢。

0 投票
4 回答
794 浏览

c++ - 接口开销

我有一个看起来像 Boost.Array 的简单类。有两个模板参数 T 和 N。Boost.Array 的一个缺点是,每个使用这种数组的方法都必须是一个带有参数 N 的模板(T 是可以的)。结果是整个程序往往是一个模板。一个想法是创建一个仅依赖于 T(类似于 ArrayInterface)的接口(仅具有纯虚函数的抽象类)。现在每个其他类只访问接口,因此只需要模板参数 T(与 N 相比,它或多或少总是已知的)。如果使用接口,这里的缺点是虚拟调用的开销(更多错失内联调用的机会)。直到这里只有事实。

但我真正的问题在于其他地方。当我使用接口扩展 Boost.Array 时,Boost.Array 的直接实例化会变慢(在一种情况下,因子 4,这很重要)。如果我删除接口,Boost.Array 和以前一样快。我了解,如果通过 ArrayInterface 调用方法存在开销,那没关系。但是我不明白如果只有一个只有纯虚拟方法的附加接口并且直接调用该类,为什么对方法的调用会变慢。

GCC 4.4.3 和 Clang 1.1 表现出相同的行为。

0 投票
1 回答
336 浏览

c++ - 如何设置虚函数的对齐方式?

我正在使用 mingw 和来自 linux 的交叉编译为 Win32 开发插件。虽然我的插件成功地被应用程序加载,我什至从应用程序获得了一个 com 接口,但我无法从那里调用函数 - 应用程序崩溃了。我认为这是由于 mingw 中接口实现的错误 vtable 对齐(这与 MSVS 完美配合)。

任何帮助将不胜感激,谢谢。

0 投票
11 回答
5662 浏览

c++ - 替代的虚函数调用实现?

C++通过虚拟机制支持动态绑定。但据我了解,虚拟机制是编译器的实现细节,标准只是指定在特定场景下应该发生的行为。大多数编译器通过虚拟表和虚拟指针来实现虚拟机制。这与虚拟指针和表的实现细节无关。我的问题是:

  1. 除了虚拟指针和虚拟表机制之外,是否有任何编译器以任何其他方式实现虚拟函数的动态调度?据我所知,大多数(读G++,微软Visual Studio)都是通过虚拟表、指针机制来实现的。那么实际上还有其他编译器实现吗?
  2. sizeof任何只有一个虚函数的类都将是该编译器上一个指针(vptr inside )this大小。那么鉴于虚拟指针和 TBL 机制本身就是编译器实现,我上面的这句话会永远成立吗?
0 投票
1 回答
9795 浏览

java - java接口是如何在内部实现的?(虚拟表?)

C++ 有多重继承。在程序集级别实现多重继承可能非常复杂,但网上有很好的描述,说明这是如何正常完成的(vtables、指针修复、thunk 等)。

Java没有多重实现继承,但它确实有多重接口继承,所以我不认为每个类只有一个vtable的直接实现可以实现它。java内部是如何实现接口的?

我意识到与 C++ 不同,Java 是 Jit 编译的,因此不同的代码段可能会以不同的方式进行优化,并且不同的 JVM 可能会做不同的事情。那么,是否有许多 JVM 遵循的一些通用策略,或者是否有人知道特定 JVM 中的实现?

此外 JVM 经常去虚拟化和内联方法调用,在这种情况下根本不涉及 vtable 或等效项,因此询问实现虚拟/接口方法调用的实际汇编序列可能没有意义,但我假设大多数 JVM 仍然保留一些如果它们无法对所有内容进行虚拟化,则可以使用类的一般表示。这个假设是错误的吗?这种表示形式看起来像 C++ vtable 吗?如果是这样,接口是否有单独的 vtables,它们如何与类 vtables 链接?如果是这样,对象实例是否可以像 C++ 中的对象实例一样具有多个 vtable 指针(指向类/接口 vtable)?对同一对象的类类型和接口类型的引用是否总是具有相同的二进制值,或者它们是否会像在需要指针修复的 C++ 中那样不同?

(供参考:这个问题询问了有关 CLR 的类似问题,并且在这篇 msdn 文章中似乎有一个很好的解释,尽管现在可能已经过时了。我找不到任何类似的 Java 内容。)

编辑:

  • 我的意思是“GCC 编译器如何实现整数加法/函数调用/等”的意义上的“实现”,而不是“Java 类 ArrayList 实现 List 接口”的意义上。
  • 我知道这在 JVM 字节码级别是如何工作的,我想知道的是 JVM 在完成加载类文件和编译字节码后会生成什么样的代码和数据结构。
0 投票
5 回答
3406 浏览

c++ - 派生类 vtable 已损坏?

需要 root 帮助导致 vtable 损坏问题(不确定是否发生了这种情况)。这是代码的非常简化的版本。

当我创建 CDerived 的一个实例并调用派生类虚拟函数时,派生_virtual_fn2 另一个函数被称为派生_virtual_fn1。

调用 base_virtual_fnx 没有问题。

这只发生在堆上创建的对象而不是本地对象。

这些类位于共享库中。我在 Linux (SLES 10) 上使用 gcc 3.4.2。此代码中没有 pragma pack 指令,并且混合了 C 和 C++ 代码(使用了 extern c)。这里可能是什么问题?

我忘了提到还有很多其他代码(可执行文件,库)

0 投票
6 回答
1616 浏览

c++ - 继承和多态的底层细节

这个问题是萦绕在我脑海中的一大疑问,也很难用语言来形容。有时它似乎很明显,有时很难破解。所以问题是这样的::

Q1。虽然 b_ptr 指向 Derived 对象,但它访问哪个 VTABLE 以及如何?因为 b_ptr -> function4() 给出了编译错误。还是 b_ptr 在派生的 VTABLE 中只能访问该大小的基类 VTABLE?

Q2。既然 Derived 的内存布局必须是 (Base,Derived) ,那么 Base 类的 VTABLE 是否也包含在 Derived 类的内存布局中?

Q3。既然Vtable基类的function1和function2指向Base类的实现,Derived类的function2指向Base类的function2,那么Base类中真的需要VTABLE吗?(这可能是我能问过的最愚蠢的问题,但在我目前的状态下我仍然对此表示怀疑,答案必须与 Q1 的答案相关 :))

请评论。

谢谢你的耐心。

0 投票
4 回答
142 浏览

c++ - 矩阵 = *((fxMatrix*)&d3dMatrix); //邪恶的?

我一直在使用

相当长一段时间。它工作得很好,直到我的屏幕变黑并在我的桌子上收到一大堆挫败感。

fxMatrix 包含 4 个 fxVector。fxVector 以前是 16 字节,现在突然变成 20 字节了。这是因为它继承了 fxStreamable,增加了 vTable。

因此,一种解决方案当然是不继承 fxStreamable,并留下评论说它必须始终为 16 字节,并且永远不会更多。

另一种解决方案是制作转换函数,并完全复制矩阵。这使它更安全,但对性能有影响。我想这是最好的主意。

另一种解决方案是根本不转换,并坚持使用 D3DXMATRIX,但这会使引擎不一致,我个人非常不喜欢这个想法。

你有什么意见?