C++ 在C++;,这个方法是调用静态绑定还是动态绑定?

C++ 在C++;,这个方法是调用静态绑定还是动态绑定?,c++,class,virtual-functions,C++,Class,Virtual Functions,以下是类定义: 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 {

以下是类定义:

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
的“vtable”中的指针应该调用
rect->draw

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

rect::draw()
不是
final
rect
是指针,所以它使用动态绑定


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

您对vtable的总体理解是正确的

我认为这本书试图说的是,编译器可能,而且通常会,优化要调用的rect->draw,而不必去vtable

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


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

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

final
会阻止其编译。它禁止重写而不是停止它。@DmitryRubanovich:As
final
方法不能被重写(因此假设没有
Square::draw
),作为优化,编译器可以调用
final
方法而不使用vtable。编译器不调用任何东西。它生成(隐喻性地)进行调用的代码。编译器无法在重写超类中的
final
方法的子类中生成代码。如果遇到此类代码,编译器必须生成编译时错误。生成忽略函数虚拟性的代码意味着破坏声明。换句话说,这不是一个编译器优化。假设a是纯虚拟基类(声明了virtual f()),B和C派生自a。B::f()是最终的,而C::f()不是。现在让我们假设D从C,B派生。根据顺序,D的f()是从C派生的。现在让我们假设f()通过类型B的指针在D的实例上被调用。如果f()的虚拟性被剥离,它将调用B::f()。而它应该根据声明调用C::f()。这将是一个编译器错误。@DmitryRubanovich:我的意思是,在类似的情况下,(第一个)调用可以被设备化。