虚拟表是否需要C++

Is virtual table necessary for C++?

本文关键字:C++ 是否 虚拟      更新时间:2023-10-16

我最近对虚拟表有疑问C++。

为什么C++使用虚拟表

=>因为编译器不知道C++实际的函数地址

--->为什么?

=>因为编译器不知道C++确切的类型(猫?狗?动物?指针"panimal"指向的对象

---为什么?编译器可以通过任何方式找出对象类型吗?

=>是的,我认为编译器可以通过跟踪对象类型来实现它。

让我们考虑对象指针获取其值的来源。 确实有 2 个来源。

  1. 另一个指针
  2. 类实例的地址"另一个指针"的价值从何而来?最终,有一个指针从"类实例"中获取其值。

因此,通过向后跟踪赋值线程到原始源对象

=>编译器能够找出指针的确切类型。

=>编译器知道被调用的确切函数的地址

=>不需要虚拟表。

对象类型跟踪保存每个类实例的虚拟表内存和虚拟表指针。

对象类型跟踪在哪些地方不起作用?

库链接。

如果库函数返回基类指针,则编译器无法追溯到原始源对象。编译器可能可以适应库代码和非库代码。对于导出的库类,请使用虚拟表。对于其他类,只需跟踪对象类型以节省内存。

我不确定上述陈述是否有错误,如果有的话,请指出。提前感谢~

在某些情况下,是的,编译器可以在编译时找出指针指向的类型。构建一个无法构建的案例非常容易。

int x;
cin >> x;
Animal* p;
if (x == 10)
    p = new Cat();
else
    p = new Dog();

如果编译器在所有情况下都可以证明对象的类型,则可以根据 as-if 规则从其生成的代码中自由删除虚拟表。

编译器能够找出指针的确切类型。

是的,但是您希望它在运行时如何调用正确的函数?编译器知道,但 c++ 没有虚拟机来告诉它在运行时传递的对象的类型,因此,需要继承类型的虚拟函数的 vtable。您是否希望编译器为导致每个虚拟函数执行的所有不同代码路径创建代码,以便它在运行时调用正确的函数?如果可能的话,这将导致更大的二进制文件。

在这个例子中,很明显,无论编译器可以进行什么静态代码分析,在ptrA->f()调用的实际方法只能在运行时知道。

#include <sys/time.h>
#include <iostream>
#include <stdlib.h>
struct A {
    virtual int f()
    {
        std::cout<<"class An";
    }
};
struct B: public A {
    int f()
    {
        std::cout<<"class Bn";
    }
};
int main()
{
    A objA;
    B objB;
    A* ptrA;
    timeval tv;
    gettimeofday(&tv, NULL);
    unsigned int seed = (unsigned int)tv.tv_sec;
    int randVal = rand_r(&seed);
    if( randVal < RAND_MAX/2)
    {
        ptrA=&objA;
    }
    else
    {
        ptrA=&objB;
    }
    ptrA->f();
    return 0;
}`