【问题标题】:What exactly are conditions for dynamic binding?动态绑定的条件究竟是什么?
【发布时间】:2014-11-13 04:15:44
【问题描述】:
class Foo
{
public:
    void f() {}

    virtual void g() {}
};

class Bar : public Foo
{
public:

    void f() {}

    virtual void g() {}
};

int main()
{
    Foo foo;
    Bar bar;

    Foo *a = &bar;
    Bar *b = &bar;

    // case #1
    foo.f();
    foo.g();

    // case #2
    bar.f();
    bar.g();

    // case #3
    a->f();
    a->g();

    // case #4
    b->f();
    b->g();
}

据我所知,在第一种和第二种情况下,编译器应该已经知道什么是类型,所以我想没有动态绑定。

但我不确定第三种和第四种情况。在第三种情况下,我认为编译器可以知道类型,如果它有点难以猜测指针指向的位置。所以可能有也可能没有动态绑定。

在第四种情况下,指向派生类对象的派生类指针是否还必须涉及动态绑定?

【问题讨论】:

  • 在第四种情况下,如果不能静态确定实际类型,那么可以,动态绑定仍然发生,因为Bar 类可以由另一个类进一步派生。

标签: c++ oop polymorphism dynamic-binding


【解决方案1】:

一般来说,只要遵循as-if 规则,C++ 编译器就可以进行积极优化。也就是说,只要程序的行为好像根本没有发生任何优化1——就可观察和而言,它们可以以任何方式进行优化定义的行为。 (如果您调用未定义的行为,那么优化很可能会改变行为,但由于行为一开始没有定义,所以这不是问题。)

无论如何,要回到正轨,这意味着编译器确实可以使用静态(编译时)绑定编译示例中的所有方法调用,因为它可以证明指针指向的对象的实际类型,并且使用静态绑定而不是动态绑定不会导致程序的可观察行为发生变化。

具体解决您的第四个问题:

...指向派生类对象的派生类指针是否还必须涉及动态绑定?

如果我们假设编译器知道所指向对象的类型,那么是的,如果您在Bar * 上调用g(),它仍然必须涉及动态绑定。这是因为它可能指向一个进一步派生Bar 类型的类的对象——也许你在另一个编译单元中引入了class Baz : Bar,或者甚至可能加载到你的程序中的一些第三方库引入了它!编译器无法知道,所以它必须假设这种情况可能发生,所以它会使用动态绑定。

但是,如果编译器能够证明 Bar::g() 不能被进一步覆盖,或者因为它是 final2 或者因为 Bar 类是 final,那么在 Bar * 上调用 g() 时,它可以使用(并且可能会使用)静态绑定。


1 该标准确实对此规则有特定的例外情况。特别是,在某些情况下,允许编译器删除对象的副本,这会省略对本来会被调用的复制构造函数的调用。如果这些构造函数具有可观察到的副作用,那么这种优化将改变程序的可观察行为。但是,该标准明确允许这样做,因为副本可能非常昂贵(想想具有一百万个元素的向量)并且因为副本构造函数不应该无论如何都有副作用。

2final 是 C++11 中的一个新关键字,用于防止类被继承或虚拟函数被覆盖。

【讨论】:

    【解决方案2】:

    应该进行静态绑定还是动态绑定取决于函数是虚拟的还是非虚拟的。指针和引用用于获得所需的运行时行为。

    对于普通对象,总是有静态绑定。

    所以,前两种情况只是静态绑定的结果。处理普通对象时,虚拟效果会丢失。

    在案例 3 和 4 中,编译器从指针中推断出静态类型,但它也将函数视为虚拟函数,因此当实际对象已知时,它会延迟绑定到运行时...

    【讨论】:

      【解决方案3】:

      虚函数调用的静态绑定需要证明调用对象的类型。如果无法证明类型,则绑定必须是动态的。

      案例 1 和 2 的类型可以证明,所以绑定可以是静态的。

      这在 3 和 4 中也是可能的,但这需要证明 ab 在分配后没有改变。

      如果我们通过引用将ab 传递给外部定义的函数,事情就会变得有趣。那时,我们需要来自翻译器链接器的信息来确定指针是否已经改变。很有可能,大多数编译器会放弃这里并动态绑定。

      【讨论】:

        猜你喜欢
        • 2013-05-27
        • 2014-03-11
        • 2019-08-28
        • 2012-04-30
        • 2011-09-05
        • 2010-12-10
        • 2014-10-28
        • 2012-08-27
        • 2010-11-12
        相关资源
        最近更新 更多