【问题标题】:In C++, is this method call static binding or dynamic binding?在 C++ 中,这个方法是调用静态绑定还是动态绑定?
【发布时间】:2016-04-18 09:15:21
【问题描述】:

这是类定义:

class Shape { public:
    virtual void draw() = 0; ...
};
class Circle : public Shape {
    public:
        void draw() { ... }
... };
class Rectangle : public Shape { public:
    void draw() { ... } ...
};
class Square : public Rectangle {
    public:
        void draw() { ... }
... };

这是客户端代码:

Square* sq = new Square; 
Rectangle* rect = new Rectangle; 
Shape* ptr_shape;
ptr_shape = sq;
ptr_shape->draw();
rect->draw();

我正在阅读的一本书说最后一条语句是静态绑定:

但是,该语句对我来说仍然是动态绑定,因为 rect->draw 应该在运行时由 rect 的“vtable”中的指针调用。

有人知道rect->draw 是静态绑定还是动态绑定?

【问题讨论】:

    标签: c++ class virtual-functions


    【解决方案1】:

    这取决于在哪里。在类的代码之外,这将始终是动态绑定。但是在对象构造期间(在继承链上的任何构造函数内部)虚拟表查找被暂停,因为子类对象可能尚未初始化。

    【讨论】:

      【解决方案2】:

      Rect::draw() 不是finalrect 是一个指针,所以它使用动态绑定。

      但是如果所有变量都在本地范围内并且所有类型都是已知的,编译器可能会使用去虚拟化作为优化。

      【讨论】:

      • final 会阻止它编译。它禁止覆盖而不是停止它。
      • @DmitryRubanovich:由于final方法不能被覆盖(所以假设没有Square::draw),作为优化,编译器可以调用final方法而不使用vtable .
      • 编译器不调用任何东西。它生成(隐喻地)进行调用的代码。编译器无法在覆盖超类中的final 方法的子类中生成代码。如果遇到此类代码,编译器必须生成编译时错误。生成忽略函数虚拟性的代码将意味着破坏声明。换句话说,它不会是编译器优化。这将是一个编译器错误。
      • 假设 A 是纯虚拟基类(声明了虚拟 f()),B 和 C 派生自 A。B::f() 是最终的,而 C::f() 不是.现在假设 D 派生自 C,B。根据顺序,D 的 f() 是来自 C 的。现在假设 f() 通过 B 类型的指针在 D 的实例上被调用。如果 f() 的虚拟性被剥离,它会调用 B::f()。虽然它应该根据声明调用 C::f() 。这将是一个编译器错误。
      • @DmitryRubanovich:我的意思是,如果像 that 那样,(第一个)调用可以被虚拟化。
      【解决方案3】:

      你对vtable的整体理解是正确的。

      我认为这本书想说的是,编译器可能并且通常会优化 rect->draw 以在不进入 vtable 的情况下调用。

      在这种情况下,编译器可以看到 rect 指向一个 Rectangle 对象。

      在大多数生产代码中,这种情况很少发生。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-02
        • 1970-01-01
        • 2012-10-29
        相关资源
        最近更新 更多