2016-01-13 3 views
6

Вот определение класса:В C++ этот метод вызывает статическое связывание или динамическое связывание?

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(); 

Книга, которую я читал сказал, что последнее утверждение является статической привязки:

enter image description here

Однако оператор все еще выглядит динамически привязанным ко мне, потому что rect->draw должен быть вызван e указатель в «vtable» rect во время выполнения.

Есть ли у кого-нибудь идеи о том, является ли rect->draw статической привязкой или динамической привязкой?

ответ

8

Rect::draw() не final и rect - указатель, поэтому он использует динамическое связывание.

Но компилятор может использовать де виртуализацию как оптимизацию, если все переменные находятся в локальной области видимости и известны все типы.

+0

'final' будет препятствовать его компиляции. Он запрещает переопределять, а не останавливает его. –

+0

@DmitryRubanovich: Поскольку метод 'final' не может быть переопределен (поэтому, не допуская' Square :: draw'), в качестве оптимизации компилятор может вызывать метод 'final', не используя * vtable *. – Jarod42

+0

компилятор ничего не называет. Он генерирует код, который (метафорически) выполняет вызовы. Компилятор не может генерировать код в подклассе, который переопределяет метод 'final' в суперклассе. Компилятор должен генерировать ошибку времени компиляции, если он встречает такой код. Генерирование кода, которое игнорировало бы виртуальность функции, означало бы нарушение объявления. Другими словами, это не будет оптимизация компилятора. Это будет ошибка компилятора. –

1

Вы полностью понимаете vtable правильно.

Я думаю, что книга пытается сказать, что компилятор может и, как правило, оптимизировать выпрямление rect->, которое будет вызываться, не переходя в таблицу vtable.

В этом случае компилятор может видеть, что rect указывает на объект Rectangle.

В большинстве производственных кодеков это будет редко.

0

Это зависит от того, где. Вне кода класса это всегда будет динамическое связывание. Во время построения объекта, хотя (внутри любого из конструкторов вверх по цепочке наследования) виртуальный поиск таблиц приостанавливается, потому что объекты дочернего класса еще не были инициализированы.