Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2.4 - Полиморфизм.doc
Скачиваний:
7
Добавлен:
02.11.2018
Размер:
60.42 Кб
Скачать

Виртуальный деструктор (virtual destructor)

Как мы видели в примере выше, при использовании обычных функций вызывается функция базового класса. Это же относится и к деструктору. Если в коде вы используете полиморфизм, то всегда объявляйте деструктор базового класса виртуальным. Иначе, при уничтожении всех объектов будет вызываться деструктор базового класса. Вот так правильно:

class Base

{ public: virtual void method () { cout << "Базовый класс\n";}

virtual ~Base() {} };

Хотя, в данном примере это не имеет значения - в данном деструкторе (и в деструкторах производных классов) ничего не происходит.

Абстрактные классы (abstract classes) и чистые виртуальные функции (pure virtual functions)

Очень часто в программах не требуется создавать объекты базовых классов. Т.е. базовые классы нужны только для того, чтобы построить иерархию классов и определить общие свойства для производных классов. Такие классы можно сделать абстрактными (abstract class). При попытке создания объекта абстрактного класса, компилятор выдаст ошибку.

Чтобы сделать класс абстрактным, нужно объявить одну из виртуальных функций чистой.

Чистая виртуальная функция (pure virtual function) как бы намекает, что она будет реализована в производных классах.

Чтобы сделать виртуальную функцию чистой (pure), нужно добавить после заголовка функции символы =0 (знак равенства и ноль):

class Base

{ public: virtual void method () =0;

virtual ~Base() =0;

};

В данном случае уже не нужно писать определение такой функции. Помимо этого теперь нельзя создавать объекты класса Base, так как он стал абстрактным.

Символы =0 необязательно добавлять ко всем виртуальным функциям, достаточно добавить к одной.

Заключение

  • При вызове обычной функции во время выполнения программы, подставляется её адрес, который был присвоен на этапе компиляции. Это раннее или статическое связывание (early/static binding).

  • При использовании указателя на функцию, в нём хранится адрес фактического местоположения реальной функции. Этот адрес был назначен на этапе компиляции (абзац выше), но указатель может менять своё значение во время выполнении программы. Это позволяет вызывать с помощью указателя разные функции. Это пример позднего/динамического связывания (late/dynamic binding). Ещё одним примером позднего связывания являются виртуальные функции.

  • Виртуальные функции объявляются с помощью ключевого слова virtual в базовом классе. При этом для базового класса и для всех производных создаётся таблица указателей на функции - виртуальная таблица методов/функций (virtual function table или vtable). Для каждого класса создаётся своя таблица. Количество элементво в таблице равно количеству виртуальных методов. В таблице хранятся фактические адреса методов, определённых в классах. Также в базовом классе объявляется дополнительное поле __vfptr (наследуется всеми производными классами) - указатель на таблицу виртуальных функций класса. Т.е. когда создаётся объект самого класса или любого производного, в нём __vfptr присваивается адрес таблицы виртуальных функций этого класса (или производных).

  • Виртуальные функции нужны в C++ для поддержки полиморфизма. Полиморфизм позволяет использовать одинаковый синтаксис для разных классов.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]