为什么使用虚拟表来解析函数调用?

时间:2010-12-22 09:01:23

标签: c++

根据我的理解,编译器验证指针赋值A *p_a = &b;,知道它指向派生类对象。但为什么需要虚拟表来解析函数调用?

class A
{
public:
    A():x(1){}
    virtual void getX() {cout << x << endl;}
private:
    int x;
};

class B : public A
{
public:
    B() : A(),x(2){}
    void getX() {cout << x << endl;}
private:
    int x;
};

int main()
{
    B b;

    A *p_a = &b;
    p_a->getX();

}

5 个答案:

答案 0 :(得分:4)

在这种情况下,编译器理论上可以在编译时解析该调用。但是呢?

A* o;
if (userClicksWidgetA())
   o = new A();
else
   o = new B();
o->method();

在编译时无法解析该调用。或者单独编译的模块有一个方法采用A*,但它对B一无所知;或者包含一无所知的子类C,它会传回给你A*?最终,vtable是对象类的唯一运行时表示。

答案 1 :(得分:2)

如果编译器足够智能,它可能能够直接调度调用,而无需通过虚拟表,因为它有足够的信息通过查看分配中的分配来了解final overrider的确切类型。之前的那条线。

通常编译器不会有那么多信息,它只会有一个指向A对象的指针,但不知道指向对象的派生类型是什么。那是 使用虚拟表的时候。基本上,存储在每个多态对象中的虚拟表指针包含最终对象的类型信息,特别是每个方法的final overrider

答案 2 :(得分:1)

每个对象都有一个指向虚拟表函数指针的指针 通过重定向虚拟表在对象上调用函数时,将调用相应的函数 即当你在代码中声明一个类型为A的对象但它确实指向一个B类型的对象时,应该在运行时调用类型B的函数实现。
但是应该调用哪个函数由vtable决定。如果没有vtable,就不可能确定是否应该调用A类的函数f()或者调用B()的f()来覆盖基类的相应函数。
这是关于多态性实现的C ++设计决策,没有其他运行时类型信息与对象关联(与java不同)

答案 3 :(得分:0)

因为这就是C ++实现多态的方式。

答案 4 :(得分:0)

因为确定在编译时调用的实际函数会使实现C ++编译器变得非常困难。

相关问题