题目:
假设如下代码
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f() {}
};
class Derived :public Base
{
public:
virtual void f() {}
};
int main()
{
Base *pb = new Derived;
pb->f();
}
在main中,因为函数 f 是虚函数,所以运行期间先通过pb所指对象的虚指针找到虚表,然后根据虚表调用虚函数 f.
那么问题是,在编译期,编译器已经能够知道:
1pb实际指向对象为派生类型Derived
2同时,pb->f()所调用的f是虚函数。
所以编译器理论上有能力在编译期直接call Derived类中的虚函数 f 的地址。为什么还要通过虚指针来调用呢?
解答:
那么问题是,在编译期,编译器已经能够知道:pb实际指向对象为派生类型Derived不,编译器不知道!只是你知道而已。你可以把它写成这样:Base*
pb = createBase();
pb->f();
然后createBase()里面是new Derived。当然,它也可以是new任何Base的子类,你甚至可以在Base *pb = new Derived;pb->f();之间插入代码,重新为pb赋值。所以编译器才需要动态绑定。
或者这样想:
1.从另外一个角度想一下,假设你的有个子类来自于一个dll,编译器根本不知道这个dll是从哪里来的,更加不可能编译期间确定它应该调用什么了。实际上它应该调用dll里面的这个实现,是runtime的。
2.假如有个数组vector<Base*>,然后你不停的取输入(stdin),如果是0就append一个new Base,如果是1就append一个new Derived,然后在某一刻你遍历这个数组并执行每个元素的虚函数,请问编译器要如何在输入都不知道的情况下静态分析出实际类型?