Процедурные типы
Указатели удобны для записи информации заданного
типа и обращения к переменным. Однако записывать адреса процедур и функций
довольно опасно. Программистам, работавшим с ранней версией Turbo Pascal,
приходилось основательно изучать способы размещения процедур и функций
в памяти и обращения к ним. Процедурные типы существенно упрощают эту проблему,
позволяя трактовать процедуры и функции как значения, которые можно присваивать
переменным и передавать в качестве параметров.
Объявление процедурного типа подобно объявлению
заголовка процедуры или функции. Единственная разница состоит в том, что
опускается имя. следующее обычно после ключевых слов procedure и function.
Вне типа Class в Object Pascal разрешены только
глобальные процедурные переменные. Это означает, что процедурной переменной
не может быть присвоена процедура или функция, объявленная внутри другой
процедуры или функции.
Кроме того, в Delphi можно применять данные процедурных
типов, представляющих собой методы. При выполнении программы можно обращаться
к определенным методам определенных переменных-объектов. Использование
методов в качестве данных процедурных типов позволяет модифицировать поведение
переменной-объекта некоторого класса, не объявляя нового класса с новыми
методами.
В Delphi указатели процедурного типа на методы применяются
для сопоставления событий с образцами текста программы. С точки зрения
синтаксиса, единственное отличие процедурного типа для метода от обычного
процедурного типа состоит в фразе of object, следующей за прототипом процедуры
или функции в случае метода. Особым образом применяется в процедурных методах
указательное значение Nil. Это единственное указательное значение, которое
можно присвоить процедурной переменной. После присвоения такого значения
процедурная переменная становится неопределенной. Состояние определенности
можно проверить с помощью функции Assigned.
Глобальные процедурные типы и процедурные типы для
методов взаимно несовместимы. Нельзя присваивать значение одного типа переменной
другого.
Физически процедурные типы в Delphi совпадают с
указательными, однако они различаются синтаксически, поэтому нельзя обращаться
к функции или процедуре через указатель. Тем не менее при обращении к процедурной
переменной задействуется именно значение указательного типа. В C/C++ переменная
может иметь тип указателя на функцию. В версиях языка С до введения стандарта
ANSI для обращения к соответствующей функции приходилось явно адресовать
указатель. В версиях С, со-ответствующих стандартам ANSI, возможны как
явная, так и неявная адресации указателей. Delphi удобна для тех, кому
близок стиль ANSI.
Тип Variant
Тип Variant предназначен для представления значений,
которые могут динамически изменять свой тип. Если любой другой тип переменной
зафиксирован, то в переменные типа Variant можно вносить переменные разных
типов. Шире всего тип Variant применяется в случаях, когда фактический
тип данных изменяется или неизвестен в момент компиляции.
Вариантные значения
При рассмотрении типа Record мы ознакомились с вариантной
частью записи, где в одном фрагменте памяти можно хранить информацию нескольких
типов. Такой метод недостаточно нагляден. Много ли пользы от того, чтобы
найти в памяти действительное значение с фиксированной запятой и интерпретировать
его, как целое! Тип Variant (не имеющий ничего общего с вариантной частью
записи) более "проворен" и полезен в управлении данными разных типов. Переменным
типа Variant можно присваивать любые значения любых целых, действительных,
строковых и булевых типов. Для совместимости с другими языками программирования
предусмотрена также возможность присвоения этим переменным значений даты/времени
и объектов OLE Automation. Кроме того, вариантные переменные могут содержать
массивы переменной длины и размерности с элементами указанных типов.
Все целые, действительные, строковые, символьные
и булевы типы совместимы с типом Variant в отношении операции присваивания.
Вариантные переменные можно сочетать в выражениях с целыми, действительными,
строковыми, символьными и булевыми; при этом все необходимые преобразования
Delphi выполняет автоматически. Можно произвольно задавать для выражении
тип Variant в форме Variant (X).
В Object Pascal определены два особых значения Variant.
Значение Unassigned применяется для указания, что вариантной переменной
пока не присвоено значение какого бы то ни было типа. Значение Null указывает
на наличие в переменной данных неизвестного типа или потерю данных. Разницу
между этими двумя значениями трудно уловить. Значение Unassigned присваивается
вариантным переменным автоматически при их создании, независимо от того,
локальная это переменная или глобальная, и является ли она частью другой,
структурной, переменной, такой как запись или массив. Unassigned означает,
что к данной вариантной переменной еще не обращались. Null же означает,
что к вариантной переменной обращались, но не ввели в нее никакой информации.
Таким образом, Null указывает, что значение вариантной переменной недействительно
или отсутствует.
Вариантные переменные предоставляют широкие возможности
формирования выражений с переменными разных типов. Однако за это приходится
платить большим, по сравнению с жестко задаваемыми типами, расходом памяти.
К тому же на выполнение операций с вариантными переменными требуется больше
времени.
Интересна проблема использования вариантной переменной
как массива. Элементы этого массива должны быть одного типа. На первый
взгляд, это вполне естественное условие. Однако элементам массива можно
присвоить и тип Variant! Тогда каждый элемент сможет содержать информацию
разных типов, в том числе массив Variant. Как правило, вариантные массивы
создаются с помощью процедуры VarArrayCreate.
Для передачи двоичной информации между контроллерами
автоматизации OLE и серверами обычно применяются вариантные массивы с элементами
varByte. Вариантные массивы типа varByte не могут подвергаться никаким
преобразованиям. Нельзя также переформатировать содержащуюся в них двоичную
информацию. Эффективный доступ к ним осуществляется с помощью процедур
VarArrayLock и VarArrayUnlock.
Элементы вариантного массива не могут иметь тип
varString. Для создания вариантных массивов со строковыми элементами следует
выбрать тип varOleStr.
Процедуры
обработки вариантных массивов
В табл. 1.9 перечислены стандартные процедуры и
функции обработки вариантных массивов, определенные в модуле System.
Таблица 1.9. Процедуры и функции обработки вариантных массивов
Процедура/функция |
Описание |
VarArrayCreate |
Создает вариантный массив с заданными пределами и типом |
VarArrayDimCount |
Возвращает число измерений данного вариантного массива |
VarArrayHighBound |
Возвращает верхний предел измерения вариантного массива |
VarArrayLock |
Фиксирует вариантный массив |
VarArrayLowBound |
Возвращает нижний предел измерения вариантного массива |
VarArrayOf |
Возвращает вариантный массив с указанными элементами |
VarArrayRedim |
Изменяет верхний предел вариантного массива |
VarArrayUnlock |
Отменяет фиксацию вариантного массива |
VarAsType |
Преобразует вариантную переменную в указанный тип |
VarCast |
Преобразует вариантную переменную в указанный тип и записывает значение |
VarClear |
Сбрасывает значение вариантной переменной |
VarCopy |
Копирует одну вариантную переменную в другую |
VarFromDateTime |
Возвращает вариантную переменную, содержащую переменную даты/времени |
VarIsArray |
Возвращает True, если вариантная переменная является массивом |
VarIsEmpty |
Возвращает True, если вариантная переменная содержит Unassigned |
VarIsNull |
Возвращает True, если вариантная переменная содержит Null |
VarToDateTime |
Преобразует вариантную переменную в значение даты/времени |
VarType |
Преобразует вариантную переменную в указанный тип и записывает значение |
В табл. 1.10 перечислены типы значении, которые
можно присваивать вариантным переменным, и вариантные типы результата.
Таблица 1.10. Вариантные типы
Тип выражения |
Вариантный тип |
Целый |
varlnteger |
Действительный, кроме Currency |
varDouble |
Currency |
varCurrency |
Строковый и символьный |
varString |
Булев |
varBoolean |
Вариантные переменные в отношении операции присвоения
совместимы с элементарными типами данных Object Pascal (Integer, Real,
String и Boolean). Все нужные преобразования Delphi выполняет автоматически.
При необходимости конкретно указать, что вариантное значение надо интерпретировать
как целое, действительное, строковое или булево, следует задать тип в форме
TypeName (V), где TypeName - идентификатор соответствующего типа, V- выражение
Variant. Задание типа изменяет только способ считывания значения из вариантной
переменной, а не само значение внутри ее. Внутреннее же представление изменяется
с помощью процедур VarAsType и VarCast.
OLE Automation
Вариантные переменные удобно применять для изменения
свойств объектов OLE Automation и вызова методов этого объекта. Чтобы инициировать
эту возможность, необходимо подключить модуль OleAuto.
Синтаксис вызова метода или обращения к свойству объекта OLE Automation
такой же, как вызова из созданного класса. Есть, однако, несколько важных
отличии. Во-первых, вызов метода объекта OLE Automation происходит по схеме
позднего связывания, т.е. компилятор не проверяет, существует ли данный
метод и правильно ли определены типы параметров. Для компилятора приемлемы
любой идентификатор метода и любое число параметров разных типов. А это
означает, что при выполнении вызванного таким образом метода может произойти
ошибка.
Что же касается идентификаторов методов объекта
OLE Automation, то они могут содержать любые алфавитные символы из международного
набора, в том числе а, ь и ш.