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

在下面我理解编译器验证指针赋值
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();

}
    
已邀请:
在这种情况下,编译器理论上可以在编译时解析该调用。但是关于?
A* o;
if (userClicksWidgetA())
   o = new A();
else
   o = new B();
o->method();
该调用无法在编译时解决。或者一个单独编译的模块,它有一个方法取一个
A*
,但它对
B
一无所知;或者包含你对它一无所知的子类
C
,它会让你回到
A*
?最终,vtable是对象类的唯一运行时表示。     
如果编译器足够智能,它可能能够直接调度调用,而无需通过虚拟表,因为它有足够的信息通过查看之前的行中的赋值来了解
final overrider
的确切类型。 通常编译器不会有那么多信息,它只有一个指向
A
对象的指针,但不知道指向对象的派生类型是什么。那是必须使用虚拟表的时候。基本上,存储在每个多态对象中的虚拟表指针包含最终对象的类型信息,特别是每个方法的
final overrider
。     
每个对象都有一个指向虚拟表函数指针的指针。 通过重定向虚拟表在对象上调用函数时,将调用相应的函数。 即当你在代码中声明一个类型为A的对象但它确实指向一个B类型的对象时,应该在运行时调用类型B的函数实现。 但是应该调用哪个函数由vtable决定。如果没有vtable,就不可能确定是否应该调用A类的函数f()或者调用B()的f()来覆盖基类的相应函数。 这是关于多态性实现的C ++设计决策,没有其他运行时类型信息与对象相关联(与java不同)     
因为这就是C ++实现多态的方式。     
因为确定在编译时调用的实际函数会使实现C ++编译器变得非常困难。     

要回复问题请先登录注册