Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lections_rus.doc
Скачиваний:
31
Добавлен:
06.02.2016
Размер:
1.41 Mб
Скачать

9.4. Выводы

Подведем итоги и формализуем все вышесказанное:

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

В Smalltalk, чисто объектно-ориентированном языке, полиморфизм охватывает все методы в системе, поэтому вся система Smalltalk является полиморфическим кластером.

Обычную функцию-член можно переопределить в наследуемых классах. Однако без атрибута virtualтакая функция-член будет связана с сообщением на этапе компиляции. Атрибутvirtual гарантирует позднее связывание в пределах полиморфического кластера.

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

Часто возникает необходимость передачи сообщений объектам, принадлежащим разным классам в иерархии. Каждый класс в иерархии отвечает на сообщение по-своему. В этом случае требуется реализация механизма позднего связывания. В С++ этот механизм реализован для виртуальных функций (объявление с использованием ключевого слова virtual).

С++ поддерживает virtual функции-члены, которые объявлены в основном классе и переопределены в порожденном классе. Иерархия классов, определенная общим наследованием, создает связанный набор типов пользователя, на которые можно ссылаться с помощью указателя базового класса. При обращении к виртуальной функции через этот указатель в С++ выбирается соответствующее функциональное определение во время выполнения.

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

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

Необходимо обратить внимание на следующие вещи:

  1. Если производный класс перегружает метод – меняется запись в таблице виртуальных функций.

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

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

Виртуальные функции позволяют управляемым классам определять различные версии функций базового класса. В С++ функции-члены класса с различным числом и типом параметров являются действительно различными функциями, даже если они имеют одно и тоже имя. Виртуальные функции позволяют переопределять в управляемом классе функции, введенные в базовом классе, даже если число и тип аргументов то же самое. Для виртуальных функций нельзя переопределять тип функции. Если две функции с одинаковым именем будут иметь различные аргументы, С++ будет считать их различными и проигнорирует механизм виртуальных функций. Для определения виртуальной функции служит ключевое словоvirtual.Виртуальная функция обязательно член класса.

В C++ существуют абстрактные виртуальные функции. Они определяются следующим образом:

virtual void foo() = 0;

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

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