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

时间:2013-08-19 13:23:04

标签: c++

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

例如:

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. 必须使用指针或引用来调用函数。
  3. 两个触发条件导致我问的问题: “当基类指针指向基类对象时,编译器是否会使用动态绑定?”

    我有谷歌搜索答案,我找到一个片段(演示是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>

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

    这让我很困惑。

3 个答案:

答案 0 :(得分:3)

它可以选择任何一个或两个,具体取决于它的智能程度和检测能力。规则是多态必须工作。如何实现这一点是一个实现细节。

如果使用动态或静态绑定可以实现相同的最终结果,就像这里的情况一样,两者都是编译器的有效选项。

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

生成的代码完全相同
int main()
{
    cout << "base class";
}

答案 1 :(得分:2)

我想这取决于编译器优化。编译器可能足够聪明,可以确定Base::show始终是被调用的,或者可能不是。您可以查看反汇编以了解相关信息。您可以使用b->Base::show()

强制进行静态绑定

答案 2 :(得分:2)

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

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

b.show()

但是,任何优化都取决于编译器是否应用它们 - 标准说即使指针指向Base对象也会发生虚拟调度,就是这样。