Механизм позднего связывания 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Механизм позднего связывания



Для каждого класса (не объекта!), содержащего хотя бы один виртуальный метод, компилятор создает таблицу виртуальных методов (vtbl), в которой для каждого виртуального метода записан его адрес в памяти. Адреса методов содержатся в таблице в порядке их описания в классах. Адрес любого виртуального метода имеет в vtbl одно и то же смещение для каждого класса в пределах иерархии.

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

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

Рекомендуется делать виртуальными деструкторы для того, чтобы гарантировать правильное освобождение памяти из-под динамического объекта, поскольку в этом случае в любой момент времени будет выбран деструктор, соответствующий фактическому типу объекта. Деструктор передает операции delete размер объекта, имеющий тип size_t. Если удаляемый объект является производным и в нем не определен виртуальный деструктор, передаваемый размер объекта может оказаться неправильным.

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

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

Виртуальный механизм работает только при использовании указателей или ссылок на объекты. Объект, определенный через указатель или ссылку и содержащий виртуальные методы, называется полиморфным. В данном случае полиморфизм состоит в том, что с помощью одного и того же обращения к методу выполняются различные действия в зависимости от типа, на который ссылается указатель в каждый момент времени.


 

Абстрактные классы

Класс, содержащий хотя бы один чисто виртуальный метод, называется абстрактным. Абстрактные классы предназначены для представления общих понятий, которые предполагается конкретизировать в производных классах. Эти классы применяются при определении данных и методов, которые будут общими для различных производных классов. Создание классов, имеющих общим только поведение, осуществляется с помощью базового класса, в котором все функции-члены объявлены в разделе public, а в разделе private данных либо очень мало, либо вовсе нет. Абстрактный класс может использоваться только в качестве базового для других классов — объекты абстрактного класса создавать нельзя, поскольку прямой или косвенный вызов чисто виртуального метода приводит к ошибке при выполнении.

Функции-члены в абстрактных классах определяются через чистые виртуальные функции. Чистые виртуальные функции – функции, которые объявлены с ключом virtual, но не определяются. Они должны быть переопределены в производных классах. В базовом классе они инициализируются с помощью идентификатора (=0). Форма записи чистой виртуальной функции:

virtual <тип возвращаемого значения> <имя функции> (<список параметров>) = 0;

Нельзя создать объект абстрактного класса, т.к. прямой или косвенный вызов чистого виртуального метода приводит к ошибке при выполнении. Сам абстрактный класс используется только в качестве базового для создания других классов.

При определении абстрактного класса необходимо иметь в виду следующее:

· абстрактный класс нельзя использовать при явном приведении типов, для описания типа параметра и типа возвращаемого функцией значения;

· допускается объявлять указатели и ссылки на абстрактный класс, если при инициализации не требуется создавать временный объект;

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

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

Пример 1

class DIsplay_medium

{

public:

virtual Point size() const = 0;

virtual Point cursor() const = 0;

virtual int move_cursor(const Point &p) = 0;

virtual Display char character() const = 0;

virtual string Tine() caonst = 0;

virtual void add (DIsplar char ch) = 0;

virtual void add(const String &s) = 0;

virtual void clear();

};

Пример 2

Class Gambler {

Public:

Virtual int move()=0;

};


 



Поделиться:


Последнее изменение этой страницы: 2021-07-18; просмотров: 44; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.216.38.221 (0.011 с.)