繁体   English   中英

当基类指针指向基类对象时,编译器是否将使用动态绑定?

[英]when a base class pointer point to a base class object whether the compiler will use dynamic binding?

我知道,当使用指向派生类对象的基类指针调用虚拟函数时,编译器将使用动态绑定来调用派生版本。 但是,当使用指向基类对象的基类指针来调用虚拟函数时,编译器是否使用动态绑定或静态绑定来调用虚拟函数?

例如:

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?
}

因为我的英语很不好,所以我想使我的问题尽可能简单,但是我将在下面详细介绍我的问题:

实际上,问题源于我正在总结如何触发动态绑定。 首先,我总结一下触发条件:

  1. 该功能必须是虚拟功能。
  2. 必须使用指针或引用来调用该函数。

这两个触发条件引起了我问的问题:“当基类指针指向基类对象时,编译器是否将使用动态绑定?”

我有谷歌搜索答案,我发现一个片段(演示在这里 ):

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.基类中的功能必须在派生类中被覆盖。

现在,根据这三个触发条件,当使用指向基类对象的基类指针调用虚拟函数时,编译器将使用静态绑定来调用虚拟函数,因为虚拟不会被覆盖。

但是,当使用指向派生类对象的派生类指针来调用虚拟函数时,它将使用动态绑定,因为虚拟被覆盖了。

这让我很困惑。

它可以根据其智能程度和检测能力来选择其中一个,也可以不选择。 规则是多态性必须起作用 如何实现这一点是实现细节。

如果通过动态绑定或静态绑定都可以达到相同的最终结果(如此处所示),则这两个都是编译器的有效选项。

在您的情况下,根本不需要调用该函数-生成的代码可能与由生成的代码完全相同

int main()
{
    cout << "base class";
}

我猜这取决于编译器优化。 编译器可能很聪明, Base::show始终是被调用的那个,也可能不是。 您可以查看反汇编以找出答案。 您可以使用b->Base::show()强制进行静态绑定

简短的回答:不可以。至少在理论上不可以。 因为从理论上讲,编译器不知道指针是否指向BaseDerivedYetAnotherDerived对象。 因此,无论对象的动态类型如何,它都必须应用相同的机制。

但是:实际上,编译器具有优化器,能够识别动态类型已知的一些用例。 在您的情况下,它可以检测到别名,这意味着它知道pb指向b并且它是一个局部变量并且不能同时更改,因此它知道实际上您正在调用b.show()并将输出缩写为反映这一事实并摆脱虚拟派遣。 类似的优化是可能的,例如在以下代码中:

auto pb = make_unique<Base>();
pb->show();

但是,任何优化都取决于编译器是否要应用它们-标准指出,即使指针指向基础对象,虚拟调度也会发生,仅此而已。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM