c++ - 为什么 C++ RTTI 需要虚拟方法表?

标签 c++ rtti

为什么 C++ RTTI 要求类有一个虚拟方法表?虽然使用表作为多态向上转换的手段似乎是合理的,但从设计的角度来看,它似乎并不是严格要求的。例如,该类可以包含传递信息的散列或唯一标识符。
对于认为这个问题过于琐碎的 C++ 专家,这将有助于这个问题的发帖者(他是 C++ 的一个谦逊的初学者)从 RTTI 的设计角度解释为什么需要 vtables,以及什么是其他设计方法(而不是使用 vtables)来实现 RTTI(以及它们为什么工作/不工作以及 vtables)。

最佳答案

从语言的角度来看,答案是:它不是 . C++ 标准中没有任何地方说明如何实现虚函数。编译器可以自由地确保调用正确的函数,但它认为合适。
那么,通过替换 v 可以获得什么?指针 (不是 v )具有 id 并删除 vtable? (用 id 替换 vtable 并没有任何帮助,一旦你解决了 vptr,你就已经知道运行时类型了)
运行时如何知道实际调用哪个函数?
考虑:

template <int I>
struct A {
  virtual void foo() {}
  virtual void bar() {}
  virtual ~A() {}
};

template <int I>
struct B : A<I> {
  virtual void foo() {}
};
假设你的编译器给出 A<0> ... 让我们称之为 视频 ... 0 和 A<1>视频 1. 请注意 A<0>A<1>在这一点上是完全不相关的类。如果你说 a0.foo() 会发生什么?在哪里 a0A<0> ?在运行时,非虚拟函数只会导致静态调度 call .但是对于虚函数,调用函数的地址必须在运行时确定。
如果你只有 vid 0,你仍然需要编码你想要的功能。这将导致 if-else 分支的森林,以找出正确的函数指针。
if (vid == 0) {
  if (fid == 0) {
    call A<0>::foo();
  } else if (fid == 1) {
    call A<0>::bar();
  } /* ... */
} else if (vid == 1) {
  if (fid == 0) {
    call A<1>::foo();
  } else if (fid == 1) {
    call A<1>::bar();
  } /* ... */
} /* ... */
这将失控。因此,表。添加标识 foo() 的偏移量以 A<0> 为基数的函数的 vtable 并且您有要调用的实际函数的地址。如果您有 B<0>相反,将偏移量添加到该类的表的基指针。
理论上,编译器可以为此发出 if-else 代码,但事实证明,指针添加速度更快,生成的代码更小。

关于c++ - 为什么 C++ RTTI 需要虚拟方法表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63025648/

相关文章:

c++ - 使用替换的 operator new 进行 Clang 链接时优化会导致 valgrind 中的 free()/delete 不匹配

c++ - 在 DLL 中运行后,变量一直设置为 NULL

delphi - 访问 TWinControl 的 protected 事件

c++ - 在扩展模板的类中初始化静态常量

java - 在 Java 中避免 RTTI

c++ - 为什么所有像素值的锁定位都返回 -842150451?

c++ - 单链表显示函数中的段错误

c++ - 从 C++ 程序刻录 CD/DVD

c++ - 在 GUI 设计中避免 dynamic_cast

delphi - 如何获取内存中对象的数据集?