考虑基类中的一个
virtual function
是派生类中的not overriden
的情况。然后使用base class pointer to a derived class object
调用虚拟函数。
我知道函数调用将在编译时解析为基类中的函数。
问题
由于函数在派生类中没有被重写,因此函数调用会在编译时绑定到函数实现吗?还是会将绑定延迟到运行时?
很可能会在编译时解决
大多数现代编译器都足够聪明,可以在编译时解决动态调度问题,前提是有足够的可信信息供他们决定。
在这种情况下,由于Derived类中没有提供重写函数,因此智能编译器应该能够在编译时静态解析函数调用。
为了能够在编译时猜测实现,编译器必须知道指向对象的类型。。。例如
MyBaseClass *p = new MyDerivedClass;
p->foo();
在上面的例子中,编译器应该足够聪明,能够猜测指向对象的类型,并且调度(假设编译器使用VMT解决方案进行后期绑定)应该不需要VMT查找,即使方法是虚拟的。
然而,例如在以下中
void doit(MyBaseClass *p)
{
p->foo();
...
}
CCD_ 4的代码不能知道所指向的对象的类型,因此该调用将需要VMT查找。请注意,C++语言的设计使编译器可以一次工作一个编译单元,因此编译器不可能知道程序中只有一个派生类型(另一个模块的源代码可以定义不同的派生类,即使是在本地未命名的命名空间中,函数也会被重写)。
当然,函数doit
最终可能会被编译器内联,因此如果可以推断类型,调用doit
的特定调用站点可能确实不需要查找。但是,如果doit
函数是公开可见的(例如,它不在未命名的命名空间或静态自由函数中),则当从其他编译单元调用时,为其生成的机器代码将包括VMT查找。
请注意,在所有关于何时需要查找的讨论中,如果虚拟函数是否已被覆盖,则完全无关。原因是,如果虚拟函数没有被覆盖,并且调度是用VMT实现的,那么派生类VMT将在该槽中具有基本实现的地址。
换句话说,p->foo()
被编译为
p->__VMT__[__FOO_VMT_SLOT_NUMBER__](p); // Dynamic dispatch
或
__DERIVED_FOO_IMPLEMENTATION__(p); // Type known at compile time
其中CCD_ 9是存储在VMT中的函数指针,并且它可以等于基实现的地址。