1

考虑virtual function基类not overriden中的 a 在派生类中的情况。然后使用一个base class pointer to a derived class object虚函数被调用。

我知道函数调用将在编译时解析为基类中的函数。

问题

由于函数在派生类中没有被覆盖,函数调用会在编译时绑定到函数实现,还是会延迟绑定直到运行时?

4

2 回答 2

1

很可能它会在编译时解决。
如果有足够可靠的信息供他们决定,大多数现代编译器都足够聪明,可以在编译时解决动态调度问题。
在这种情况下,由于 Derived 类中没有提供覆盖函数,因此智能编译器应该能够在编译时静态解析函数调用。

于 2012-01-25T06:29:28.970 回答
1

为了能够在编译时猜测实现,编译器必须知道指向对象的类型......例如

MyBaseClass *p = new MyDerivedClass;
p->foo();

在上面,编译器应该足够聪明地猜测指向对象的类型,并且即使方法是虚拟的,分派(假设编译器使用 VMT 解决方案进行后期绑定)也不需要 VMT 查找。

但是例如在下面

void doit(MyBaseClass *p)
{
    p->foo();
    ...
}

的代码doit无法知道指向的对象的类型,因此调用将需要 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

其中__DERIVED_FOO_IMPLEMENTATION__是存储在 VMT 中的函数指针,它可能等于基实现的地址,也可能不等于派生类中的函数是否被覆盖。

于 2012-01-25T07:27:02.150 回答