C++虚拟指针及其机制

t1rydlwq  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(170)

我提出这一点是因为在阅读了许多帖子和答案后,我仍然没有得到我的答案。如果是这样的话,请标记为副本。
在C中,虚函数是通过虚指针和虚表实现的。
然而,我不确定C
编译器如何在运行时破译哪个虚拟指针?
在下面简单的情况下:

class Base {
public:
    virtual foo() {}
}

class Derived: public Base {
public:
    foo() override {}
}

int main() {
  D* p_derived = new Derived();
  B* p_base = p_derived;

  p_derived->foo();
  p_base->foo();
}

我知道p_derived->foo()将为Derived::vtable(命名)查找Derived::vptr本身,然后Derived::foo()p_base->foo()遵循与Derived::vptr -> Derived::vtable -> Derived::foo()相同的路径。但是p_base->foo()如何找到Derived::vptr,即使它的静态类型是Base*?是什么阻止了p_base查找Base::vptr
非常感谢

nhjlsmyf

nhjlsmyf1#

我真的认为相关的答案有你需要知道的一切,但可能有一点缺失。
vtable是实现定义的,所以根据标准,任何工作都是可以的。
一种方法是让实际的vtable是const static,并且在每个构造函数中,单个指针被更新为指向每个新的类vtable。这有双重间接惩罚,但一个好处是恶意软件不可能覆盖函数指针。
另一种方法是有一个表,又名数组,指针。虚拟指针表:vtable。在这个方法中,在每个构造函数中设置每组指针。或者至少看起来是这样的:优化器可以做奇怪的事情。
多重继承、多重虚拟继承等会使事情变得非常复杂。甚至可以有嵌套的vtables:table指向其他table!
当然,我们会得到整个程序的优化。Unix上的LTO。MSVC中的LTCG等优化器可以遍历程序,如果它可以确定虚拟调用只能转到一个目标函数,那么它将用非虚拟直接调用替换该调用。然后重新运行内联传递。配置文件定向优化甚至可以采用一个变量虚函数,并确定它在80%的时间内正在调用类A。然后它可能总是调用A,并进行离线检查以确定它实际上是B还是其他。
但在您所设计的简单情况下,类Base有一个vtable,其中有一个指向foo的函数指针。当Base()构造函数运行时,它被设置为Base::foo。在Derived()运行之后,它被设置为Derived::foo()
如果没有复杂的虚继承或多重继承,基类(在本例中为Base)始终位于结构的前面。所以指向Base的指针总是指向前面。vtable在哪里指向Derived的指针也指向前面。这两个类使用相同的vtable,并调用其中设置的任何函数。

q3qa4bjr

q3qa4bjr2#

p_base只是一个指针而不是示例。我认为p_base可以访问的vptr是p_derived的vptr。

相关问题