-2

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

为什么 C++ 使用虚拟表

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

--->为什么?

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

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

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

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

  1. 另一个指针
  2. 类实例的地址“另一个指针”在哪里获得它的值?最终,有一个指针从“类实例”中获取它的值。

因此,通过将分配线程向后跟踪到原始源对象

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

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

  => 不需要虚拟表。

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

对象类型跟踪在哪里不起作用?

图书馆链接。

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

不知道以上说法是否有错误,如有错误请指出。先谢谢了~

4

3 回答 3

1

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

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

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

于 2014-11-20T07:57:11.423 回答
0

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

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

于 2014-11-20T07:50:01.323 回答
0

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

#include <sys/time.h>
#include <iostream>
#include <stdlib.h>

struct A {
    virtual int f()
    {
        std::cout<<"class A\n";
    }
};

struct B: public A {
    int f()
    {
        std::cout<<"class B\n";
    }
};

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;
}`
于 2017-02-01T20:14:09.653 回答