我知道当使用指向派生类对象的基类指针来调用虚函数时,编译器将使用动态绑定来调用派生版本。 但是当使用指向基类对象的基类指针来调用虚函数时,编译器是否使用动态绑定或静态绑定来调用虚函数 功能
例如:
class Base
{
public:
virtual void show()
{
cout << "base class";
}
}
int main()
{
Base *pb; //Base class pointer
Base b; //Base class object
pb = &b;
pb->show(); //Is static binding or dynamic binding?
}
因为我的英语非常糟糕,所以我想让我的问题尽可能简单,但我会在下面更详细地描述我的问题:
实际上问题源于我总结了如何触发动态绑定。 首先,我总结了触发条件:
两个触发条件导致我问的问题: “当基类指针指向基类对象时,编译器是否会使用动态绑定?”
我有谷歌搜索答案,我找到一个片段(演示是here):
struct A {
virtual void f() { cout << "Class A" << endl; }
};
struct B: A {
//Note that it not overrides A::f.
void f(int) { cout << "Class B" << endl; }
};
struct C: B {
void f() { cout << "Class C" << endl; }
};
int main() {
B b; C c;
A* pa1 = &b;
A* pa2 = &c;
// b.f();
pa1->f();
pa2->f();
}
以下是上例的输出:
"Class A"
"Class C"
根据pa1->f()
输出Class A
,我总结了第三个触发条件:
3.必须在派生类中重写基类中的函数。
现在根据三个触发条件,当使用指向基类对象的基类指针来调用虚函数时,编译器将使用静态绑定来调用虚函数,因为虚方法没有被覆盖。 / p>
但是当使用派生类指针指向派生类对象来调用虚函数时,它将使用动态绑定,因为虚拟被覆盖。
这让我很困惑。
答案 0 :(得分:3)
它可以选择任何一个或两个,具体取决于它的智能程度和检测能力。规则是多态必须工作。如何实现这一点是一个实现细节。
如果使用动态或静态绑定可以实现相同的最终结果,就像这里的情况一样,两者都是编译器的有效选项。
在您的情况下,根本不需要调用该函数 - 生成的代码可能与
生成的代码完全相同int main()
{
cout << "base class";
}
答案 1 :(得分:2)
我想这取决于编译器优化。编译器可能足够聪明,可以确定Base::show
始终是被调用的,或者可能不是。您可以查看反汇编以了解相关信息。您可以使用b->Base::show()
答案 2 :(得分:2)
简短回答:不。至少在理论上不是。因为从理论上讲,编译器不知道指针指向Base
,Derived
还是YetAnotherDerived
对象。因此,无论对象的动态类型如何,它都必须应用相同的机制。
但是:在实践中,编译器具有优化器,能够识别动态类型已知的一些用例。我的情况是它可以检测到别名,这意味着它知道pb
指向b
并且它是一个局部变量并且不能同时更改,所以它知道实际上你正在调用{{1并将缩写输出以反映该事实并摆脱虚拟调度。类似的优化是可能的,例如在这段代码中:
b.show()
但是,任何优化都取决于编译器是否应用它们 - 标准说即使指针指向Base对象也会发生虚拟调度,就是这样。