67824

Дополнительные возможности версии языка Object Pascal for Delphi

Лекция

Информатика, кибернетика и программирование

Начиная с версии Delphi 4, была реализована концепция перегрузки функций (overloading), которая позволяет иметь несколько различных функций или процедур с одинаковым именем, но с разными списками параметров. Такие процедуры и функции должны быть описаны с применением директивы overload...

Русский

2014-09-15

229.5 KB

0 чел.

Дополнительные возможности версии языка Object Pascal for Delphi.

Комментарии

Средства языка включают еще один вид комментария – строчный. Комментарий представляет собой список символов, расположенный между символом // и концом строки:

// это пример комментария

HasDefVal('hello'); // Для параметра используется значение по умолчанию

Константы

В Object Pascal не требуется указывать тип константы. Компилятор автоматически выделяет необходимую память, основываясь на инициализирующем значении, например:

const

 ADecimalNumber = 3.14;

 i = 10;

 ErrorString    = 'Danger, Danger, Danger!';

В то же время  определять тип константы не запрещается, что дает возможность контроля над тем, каким образом компилятор будет трактовать константу во время работы над программой:

const

ADecimalNumber : Double = 3.14;

i : Integer = 10;

ErrorString : String = 'Danger, Danger, Danger!';

При объявлении констант (const) и переменных (var) в языке Object Pascal допускается использование функций, вычисляемых во время компиляции. К этим функциям относятся Ord(), chr(), Trunc(). Round(), High(), Low() и Size0f().

Раздел процедур и функций.

Скобки

   Добавление скобок при вызове функции или процедуры без параметров: считаются корректными оба варианта вызова.

Forml.Show;

Forml.Show();

Возможность перегрузки

Начиная с версии Delphi 4, была реализована концепция перегрузки функций (overloading), которая позволяет иметь несколько различных функций или процедур с одинаковым именем, но с разными списками параметров. Такие процедуры и функции должны быть описаны с применением директивы overload:

procedure Hello(I: Integer); overload;

procedure Hello(S: String); overload;

procedure Hello(D: Double); overload;

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

Значения параметров по умолчанию

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

procedure HasDefVal(S: String ; I: Integer =0);

Подобное объявление означает, что процедура HasDefVal может быть вызвана двумя путями. В первом случае – как обычно, с указанием обоих параметров:

HasDefVal('hello',26);

Во втором случае можно задать только значение параметра S, а для параметра iиспользовать значение, установленное по умолчанию:

HasDefVal('hello'); // Для параметра i используется значение по умолчанию

При использовании значений параметров по умолчанию следует помнить:                                                          

• параметры, имеющие значения по умолчанию, должны располагаться в конце списка параметров;

• значения по умолчанию могут присваиваться только параметрам обычных типов, указателям или множествам;

• параметр по умолчанию может передаваться только по значению либо с модификатором constн не может вызываться по ссылке или быть нетипизированным параметром).

Процедуры увеличения и уменьшения

Процедуры увеличения и уменьшения генерируют оптимизированный код для добавления или вычитания единицы из целой переменной.

Процедуры Inc() и Dec() можно вызывать как с одним, так и с двумя параметрами. Пример вызова этих процедур с двумя параметрами:

lnc(variable,3);

Dec(variable,3);

В данном случае выполняется увеличение (уменьшение) переменной variable на 3.

Типы данных Object Pascal

Одно из основных и важнейших свойств языка Object Pascal – строгая типизация данных.  Компилятор Object Pascal не допустит вызова функции с типом указателя, отличным от того, который описан в объявлении этой функции. Однако в функцию, параметр которой описан как нетипизированный указатель, можно передавать указатели любых типов.

Сравнение типов данных

Основные типы данных Object Pascal схожи с типами данных языков С или Visual Basic. В табл. 2.5 приведено сравнение типов данных этих языков. Это отличный справочный материал, который будет полезен при вызове функций из динамически компонуемых библиотек, созданных другими компиляторами.

Таблица 2.5. Сравнение типов разных языков программирования.

Оператор

Object Pascal

С

Visual Basic

Java

8-битовое целое со знаком

Shortint

char

Нет

byte

8-битовое целое без знака

Byte

unsigned char

Нет

16-битовое целое со знаком

Smallint

short

short

Short

16-битовое целое без знака

Word

unsigned  short

Нет

32-битовое целое со знаком

Integer,Longint

int,long

integer

Int

32-битовое целое без знака

Cardinal,Longword

unsigned  long

Нет

64-битовое целое со знаком

Int64

int64

Нет

long

4-байтовое вещественное

Single

float

Single

float

6-байтовое вещественное

real48

Нет

Нет

8-байтовое вещественное

Double

Double

Double

Double

10-байтовое вещественное

extended

long double

Нет  

64-битовое денежное

currency

Нет

currency

8-битовое дата/время

TdataTime

Нет

Data

16-байтовый вариант

Variant,OleVariant,TvarData

Variant*,OleVariant*

По умолчанию

1-байтовый символ

Char

Char

Нет

2-байтовый символ

WideChar

Wchar

Нет

Char

Строка фиксированной длинны

ShortString

Нет

Нет

Динамическая строка

AnciString

AnciString*

$

Строка с завершающимся нулевым символом

Pchar

char*

Нет

Строка 2-байтовых символов с завершающимся нулевым символом

Pwidechar

Lpcwstr

Нет

Динамическая 2-байтовая строка

WideString

WideString*

Нет

1-байтовое булево

Boolean,ByteBool

(Любое 1-байтовое)

Нет

Boolean

2-байтовое булево

Wordbool

(Любое 2-байтовое)

Boolean

4-байтовое булево

Bool,LongBool

Bool

Нет

                                                                                          

Символьные типы

В Delphi существует три символьных типа.

  •  AnsiChar – стандартный 1-байтовый символ.
  •  WideChar – 2-байтовый символ Unicode.
  •  Char –  это тип, эквивалентный AnsiChar (однако Borland предупреждает, что в последующих версиях он может измениться и стать эквивалентным WideChar).

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

 Различные строковые типы

Object Pascal имеет несколько различных типов строк:

  •  AnsiString – основной тип строки в Object Pascal, состоящей из символов AnsiChar и теоретически не имеющий ограничений по длине. Этот тип совместим со строками с завершающим нулевым символом.
  •  ShortString– остался в языке для обратной совместимости Delphi 1. Максимальная длина этой строки – 255 символов.
  •  WideString – по своей сути сходен с AnsiString. Единственное отличие состоит в том, что данная строка состоит из символов типа WideChar.
  •  PChar – представляет собой указатель на строку с завершающим нулевым символом, состоящую из символов типа Char.
  •  PAnsiChar – указатель на строку AnsiChar с завершающим нулевым символом.
  •  PWideChar – указатель на строку WideChar с завершающим нулевым символом.

   По умолчанию при объявлении строковой переменной компилятор полагает, что создается строка типа AnsiString:

var   S: string;               // Переменная S имеет тип AnsiString

Для изменения принимаемого по умолчанию типа строки используется директива компилятора $Н. Ее положительное (по умолчанию) значение определяет использование в качестве стандартного строчного типа AnsiString, отрицательное – ShortString. Вот пример использования директивы $Н для изменения строчного типа, выбираемого по умолчанию:

var

 {$Н-}

Sl: String;               // Переменная S1 имеет тип ShortString

 {$Н+}

S2: String;             // Переменная S2 имеет тип AnsiString

Исключением из этого правила являются строки, объявленные с установленным фиксированным размером. Если заданная длина не превышает 255 символов, такие строки всегда имеют тип ShortString:

var

 S; String[63];          // Это строка типа ShortString размером 63 символа

Тип AnsiString

С появлением  типа AnsiString отменили 255-символьное ограничение на длину строки.

Хотя в использовании строка AnsiString практически ничем не отличается от своей предшественницы, память для нее выделяется динамически, а для ее освобождения применяется технология "сборки мусора" (garbage collect). Благодаря этому AnsiString является типом с управляемым временем жизни (lifetime-managed). Object Pascal сам автоматически выделяет память для временных строк, так что вам не придется беспокоиться об этом, а также сам заботится о том, чтобы строка всегда была с завершающим нулевым символом.

Типы с управляемым временем жизни :

Помимо AnsiString, в Delphi существует несколько других типов данных с управляемым временем жизни. Это динамические массивы WideString, Variant, OleVariant, interface и dispinterface.

Строковые операции

Добавить одну строку в конец другой можно с помощью оператора + или функции Concat(). Предпочтительнее использовать оператор +, так как функция Concat() сохранена в основном из соображений обратной совместимости.

Concat( ) – одна из множества особых функций и процедур (подобно ReadLn() и WriteLn()), которые не имеют объявления в языке Object Pascal, функции и процедуры такого типа отличаются тем, что могут принимать необязательные параметры или иметь неопределенное количество параметров.

Длина и размещение в памяти

При первом объявлении строка AnsiString не имеет длины, а значит, память для ее значения не выделяется. Чтобы выделить память строке, следует либо присвоить ей некоторое строковое значение (например, литерал), либо использовать процедуру SetLength(S,n), где S-строка, а n – количество символов, размещенных в памяти.

Совместимость с API Win32

Как указывалось ранее, строка типа AnsiString всегда завершается нулевым символом Поэтому такая строка вполне совместима с функциями API Win32 или любыми другими, не пользующими параметры типа PChar. Все, что в данном случае необходимо, – это преобразование типа string в тип PChar (о преобразовании типов в Object Pascal можно узнать в раз деле "приведение и преобразование типов" этой же главы).

     Проявляйте определенную осторожность при приведении типов string к типу PChar. Поскольку string – это тип с управляемым временем жизни, следует обратить внимание на область видимости соответствующих переменных. Так, если вы делаете присвоение типа Р := PChar (Str) и область видимости Р больше, чем Str,результат может оказаться неправильным.

Вопросы переносимости

При переносе на новую 32-битовую платформу старых 16-битовых приложений, созданных с помощью Delphi 1.0, вам необходимо помнить следующее.

  •  Там, где применялся тип PString (указатель на ShortString), следует использовать тип String. Помните, что AnsiString представляет собой указатель на строку.
  •  Вы больше не можете использовать нулевой элемент строки для получения ее длины. Вместо этого следует прибегнуть к функции Length() и процедуре SetLength() для определения или установки нового значения длины строки.
  •  Для приведения типов строк между String и PChar больше не требуются функции StrPas() и StrPCopy(). Как уже указывалось, можно выполнять прямое преобразование типа AnsiString в PChar. При копировании содержимого PChar в AnsiString можно использовать обычное присвоение: StringVar := PCharVar.

Тип ShortString

 ShortString – это тип String в Delphi 1.0, он же тип с байтом длины строки. Директива компилятора $Н позволяет выбрать, какой именно тип будет пониматься под именем StringAnsiString или ShortString.

В памяти строка ShortString представляет собой массив символов, причем нулевой элемент этого массива содержит длину строки. Последующие символы составляют содержание строки, при этом ее максимальная длина не может превышать 255 байт, а вся строка в памяти не может занимать более 256 байт (255 байт строки и один байт длины).  При работе со строками ShortString  не нужно беспокоиться о выделении памяти для временных строк или ее освобождении – всю эту работу компилятор берет на себя.

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

Тип WideString

Это тип строки с управляемым временем жизни, подобный типу AnsiString. Оба этих типа являются динамически распределяемыми. Они подвергаются процедурам сборки мусора и даже по Назначению схожи. Однако между типами WideString и AnsiString имеются три важных отличия.

  •  Строка WideString состоит из символов WideChar, что делает ее совместимой со строками Unicode.
  •  Строки WideString используют память, выделенную с помощью функции API SysAllocStrLen(), что делает их совместимыми со строками OLE BSTR.
  •  В строках WideString отсутствует счетчик ссылок, поэтому любое присвоение одной строки другой приводит к выделению памяти и копированию строки. Это делает данный тип строк менее эффективным, чем AnsiString, с точки зрения производительности и использования памяти.

      Для упрощения работы со строками этого типа Object Pascal перегружает функции Concat (), Copy (), Insert (), Length (), Pos () и SetLength (), а также операторы +, = и<> для работы с WideString.

Строки с завершающим нулевым символом

     Ранее в этой главе упоминалось, что в Delphi имеется три различных типа строк с завершающим нулевым символом: PChar, PAnsiChar и PWideChar. Это строки с завершающим нулем для каждого из трех строковых типов Delphi.Будем ссылаться на все эти типы как на тип PChar. Тип PChar в основном обеспечивает обратную совместимость с Delphi 1.0 и работу с Win32 API, широко использующим строки с завершающим нулевым символом. Тип PChar определяется как указатель на строку с завершающим нулевым символом. В отличие от строк AnsiString и WideString, память для строк типа PChar автоматически не выделяется (и не освобождается). Это значит, что для тех строк, на которые указывают данные указатели, память потребуется выделять вручную – с помощью одной из существующих в Object Pascal функций выделения памяти.

      Обычно выделение памяти осуществляется с помощью функции StrAlloc(), однако для создания буферов PChar можно применять и другие функции, такие, например, как AllocMemf(), GetMem(), StrNew() или даже функции API VirtualAlloc(). Каждой функции соответствует функция освобождения памяти (табл. 2.6).

Таблица 2.6. Функции выделения и освобождения памяти

Функция выделения памяти

Функция освобождения памяти

AilocMem()

FreeMem()

GlobalAlloc()

GlobalFree()

GetMem()

FreeMem()

New()

Dispose()

StrAlloc()

StrDispose()

StrNew()

StrDispose()

VirtualAlloc()

VirtualFree()

Для объединения двух строк следует использовать функцию StrCat() – при работе с PChar нельзя применять оператор +, как это делается в случае со строками типа AnsiString или ShortString.

Тип Variant

В Delphi 2,0 был введен новый мощный тип данных – Variant. В основном его назначение

состояло в поддержке автоматизации OLE, где тип данных Variant используется очень широко.

Тип Variant является инкапсуляцией вариантов OLE.

В Delphi 3 для этой же цели был введен еще один новый тип данных – OleVanant, полностью идентичный типу Variant, за исключением того, что он может вмещать только те типы, которые являются совместимыми с OLE.

Динамическое изменение типа

Основное назначение типа Variant – получить возможность определять переменную, тип которой не может быть установлен во время компиляции. Это означает, что реальный тип такой переменной может изменяться в процессе выполнения программы.

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

Структура определения данных типа Variant

Структура определения данных типа Variant описана в модуле System и выглядит следующим образом:

type

PVarData = ^TVarData;

TVarData = packed record

       VType: Word;

Reserved1, Reserved2, Reserved3: Word;

case Integer of

varSmallint:        (VSmallint: Smallint);

varlnteger:          (VInteger: Integer);

varSingle:           (VSingle: Single);

varDouble;          (VDouble: Double);

varCurrency:       (VCurrency: Currency);

varDate;               (VDate: Double);

varOleStr:            (VOleStr: PWideChar);

varDispatch:        (VDispatch: Pointer);

varError:              (VError; LongWord);

varBoolean:         (VBoolean; WordBool);

varUnknown:       (VUnknown: Pointer);

varByte:               (VByte: Byte);

varString:             (VString: Pointer);

varAny;                (VAny; Pointer);

varArray:             (VArray: PVarArray);

varByRef:            (Vpointer:Pointer);

end.

{ Коды типов Variant }

const

varEmpty    = $0000

varNull     = $0001

varSmallint = $0002

varlnteger = $0003

varSingle   = $0004

varDouble   = $0005

varCurrency = $0006

varDate     = $0007   '

varOleStr   = $0008

varDispatch = $0009

varError    = $OOOA

varBoolean = $OOOB

varVariant = $OOOC

varUnknown = $OOOD

varByte     = $0011

varStrArg   = $0048

varString   = $0100;

varAny      = $0101;

varTypeMask = $OFFF;

varArray    = $2000;

varByRef    = $4000;

Из приведенного выше списка видно, что Variant не может содержать ссылку на данные типа Pointer или class.

Преобразование типов для вариантов

Можно явно преобразовать выражение к типу Variant. Так, выражение Variant (X) дает в результате вариант, тип которого соответствует результату выражения X. Последнее должно быть целым, вещественным, строкой, символом, денежным или булевым типом.

Можно также преобразовывать тип Variant к другим типам

Использование вариантов в выражениях

Вы можете использовать варианты в выражениях, составленных с использованием следующих операций: +, -, =,*, / , div, mod, shl, shr, and, or, xor, not, :=, <>, <, >, <=, >=.

При использовании вариантов в выражениях Delphi принимает решение о том, как должны выполняться операторы, на основании текущего типа содержимого варианта. Например, если варианты VI и V2 содержат целые числа, то результатом выражения V1+V2 станет их сумма. Если же они содержат строки, то результатом будет их объединение. А что произойдет, если типы данных различны? В этом случае Delphi использует некоторые правила с целью определения того, какие преобразования должны быть выполнены. Так, если VI содержит строку '4.5', а V2– вещественное число, то VI будет конвертировано в число 4.5 и сложено со значением V2. Рассмотрим следующий пример:

var

VI, V2, V3: Variant;

begin

VI := '100';                   // Строка

V2 := '50';                     // Строка

V3 := 200;                    // Целое

VI := VI + V2 + V3;

end;

Исходя из сделанного выше замечания можно предположить, что в результате будет получено целое значение 350. Однако это не так. Поскольку вычисление выражений выполняется слева направо, при первом сложении складываются две строки и в результате должна получиться тоже строка, имеющая значение ' 10050'. А уже затем полученный результат будет преобразован в целое значение и просуммирован с третьим целочисленным операндом, в результате чего будет получено значение 10250.

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

Неплохая идея при использовании преобразования типов варианта – задание явного преобразования во время компиляции. Так. в случае -даже такой обычной операции, как V4 ;= V1*V2/V3, в процессе выполнения Delphi рассматривает множество вариантов преобразования типов для того, чтобы найти наиболее подходящий. Явное же указание типов, например V4 := Integer (VI)*Double(V2)/ Integer (V3), позволяет принять решение еще на стадии компиляции, избежав тем самым излишних затрат времени при работе программы. Правда, при этом нужно точно знать, какой тип данных содержится в варианте.

Пустое значение и значение Null

Следует отдельно обсудить два специальных значения поля VType. Первое– varEmpty– означает, что варианту пока не назначено никакого значения. Это начальное значение варианта, которое компилятор устанавливает при входе переменной в область видимости. Второе значение – varNull – отличается от varEmpty тем, что оно представляет реально существующее значение переменной, которое равно Null. Это отличие особо важно при работе с базами данных, где отсутствие значения и значение Null – абсолютно разные вещи

      Еще одно отличие этих значений состоит в том, что любая попытка вычисления выражений с пустым вариантом будет приводить к возникновению исключительной ситуации:

"некорректная операция с вариантом". Однако этого не будет при использовании в выражении варианта со значением Null – результат вычисления любого выражения, в состав которого входит значение Null, всегда будет равен Null.

Если потребуется присвоить или сравнить вариант с одним из этих специальных значений, то для этого в модуле System имеется два предопределенных варианта– Unassigned и Null, у которых поля VType соответственно имеют значения varEmpty и varNull.

    За все в этой жизни приходится расплачиваться, и варианты – не исключение. Удобство работы и высокая гибкость достигаются ценой увеличения размера и замедления работы вашего приложения. Кроме того, повышается сложность сопровождения  создаваемого программного обеспечения. Естественно, бывают ситуации, когда без вариантов трудно обойтись. В частности, благодаря их гибкости, они достаточно широко применяются в визуальных компонентах, особенно в элементах управления ActiveX и компонентах для работы с базами данных. Тем не менее, в большинстве случаев рекомендуется работать с обычными типами данных. Старайтесь использовать варианты только в тех ситуациях, когда без них действительно нельзя обойтись и когда увеличение размера и замедление работы приложения – разумная плата за гибкость. Не забывайте, что использование неоднозначных типов данных приводит к появлению неоднозначных ошибок.

Варианты-массивы

Ранее упоминалось, что варианты могут представлять гетерогенные массивы. Так, следующий код синтаксически абсолютно корректен:

var

V: Variant;

I, J: Integer;

begin

I := V[J];

end;

Однако, хотя код и скомпилируется без ошибки, при ее выполнении будет сгенерирована исключительная ситуация, так как вариант V не содержит массива. Object Pascal предоставляет несколько функций, позволяющих создать вариант-массив, в частности, функций

VarArrayCreate() и VarArrayOf().

Функция VarArrayCreate()

Функция VarArrayCreate() определена в модуле System следующим образом:

function VarArrayCreate(const Bounds: array of Integer;

VarType: Integer): Variant;

При использовании функции в качестве параметров ей передаются границы создаваемого массива и код типа варианта элементов создаваемого массива. (Первый параметр представляет собой открытый массив, речь о котором пойдет ниже, в разделе "Передача параметров" этой же главы.) Например, в приведенном ниже фрагменте кода создается вариант-массив целых чисел, после чего его членам присваиваются требуемые значения.

var

V: Variant;

begin

V := VarArrayCreate([l, 4], varlnteger); // Создание массива из 4 элементов

V[l] ;= 1;

V[2] := 2;

V[3) := 3;

V[4] := 4;

end;

Однако это еще не все – передав в качестве кода тип varVariant, вы создаете вариант-массив вариантов. Это – массив, элементы которого могут содержать значения разных типов. Кроме того, точно так же можно создавать и многомерные массивы, для чего достаточно просто указать дополнительные значения границ. Например, в приведенном ниже фрагменте кода создастся двухмерный вариант-массив размерностью [1..4, 1..5].

V := VarArrayCreate((l, 4, 1, 5], varlnteger);

функция VarArrayOf ()

Эта функция определена в модуле System следующим образом:

function VarArrayOf(const Values: array of Variant):Variant;

Она возвращает одномерный массив, элементы которого были заданы в параметре Values. Ниже приведен пример создания массива из трех элементов: целого, строки и вещественного числа.

V := VarArrayOf([1, 'Delphi', 2.2]);

Функции и процедуры для работы с вариантами-массивами

Помимо функции VarArrayCreate() и VarArrayOf (), имеется еще ряд других функций и процедур, предназначенных для работы с вариантами-массивами. Они определены в модуле

System следующим образом:

procedure VarArrayRedim (var A: Variant; HighBound: Integer);

function VarArrayDimCount(const A: Variant); Integer;

function VarArrayLowBound(const A: Variant; Dim: Integer): Integer;

function VarArrayHighBound(const A; Variant; Dim: Integer): Integer;

function VarArrayLock(const A: Variant): Pointer;

procedure VarArrayUnlock(const A: Variant);

function VarArrayRef(const A: Variant): Variant;

function VarIsArray (const A: Variant); Boolean;

Функция VarArrayRedim () позволяет изменять верхнюю границу размерности самого варианта-массива. Функция VarArrayDimCount() возвращает размерность варианта-массива, а функции VarArrayLowBound() и VarArrayHighBound()– соответственно возвращают нижнюю и верхнюю границы варианта-массива. Специализированные функции VarArrayLock() и VarArrayUnlock() подробнее обсуждаются в следующем разделе.

Функция VarArrayRef () необходима для передачи вариантов-массивов серверу автоматизации OLE. Проблемы возникают в том случае, если в метод автоматизации в качестве параметра передается вариант, содержащий вариант-массив. Например:

Server.PassVariantArray(VA)

Между передачей варианта-массива и передачей варианта, содержащего вариант-массив, имеются существенные различия. Если серверу передать вариант-массив, а не ссылку на подобный объект, то при использовании приведенной выше записи сервер выдаст сообщение об ошибке. Функция VarArrayRef{) предназначена для приведения передаваемого значения к виду и типу, ожидаемому сервером:

Server.PassVariantArray(VarArrayRef(VA))

Функция VarIsArray() представляет собой простую проверку, возвращающую значение True, если передаваемый ей параметр представляет собой массив.

Инициализация большого массива с помощью функции VarArrayLock() и процедуры VarArrayUnlock()

Варианты-массивы широко используются в средствах автоматизации OLE, так как они представляют собой единственный способ передачи серверу автоматизации произвольных двоичных данных. (Отметим, что указатели не являются допустимым типом данных в среде автоматизации OLE.) Однако при неверном использовании варианты-массивы могут оказаться весьма неэффективным средством обмена данными. Рассмотрим небольшой пример:

V := VarArrayCreate([l, 10000], VarByte);

Здесь создается вариант-массив размером в 10000 байт. Предположим, что существует другой, обычный, массив того же размера и необходимо скопировать его содержимое в созданный вариант-массив. Естественный путь такого копирования – цикл, подобный тому, который приведен ниже.

begin

V := VarArrayCreate([l, 10000], VarByte);

for i ;= 1 to 10000 do V[i] - A[i];

end;

Проблема при этом заключается в огромной и совершенно излишней работе программы по определению типа и совместимости каждого элемента, его инициализации и др. Суть в том, что присвоение значений элементам массива осуществляется во время выполнения программы Для исключения выполнения всех ненужных проверок при работе программы предназначены функция VarArrayLock() и процедура VarArrayUnlock().

Функция VarArrayLock() блокирует массив в памяти так, что нельзя будет переместить его или изменить его размеры. Она возвращает указатель на данные массива. Процедура VarArrayUnlock() деблокирует массив, разрешая его перемещение в памяти и изменение его размеров. После блокировки массива для заполнения его данными можно воспользоваться более эффективными методами, например, такими как процедура Move(). Приведенный ниже пример позволяет инициализировать тот же массив значительно более эффективным методом.

begin V := VarArrayCreate([l, 10000], VarByte);

P := VarArrayLock(V);

try

Move(A, P\ 10000);

finally VarArrayUnlock(V)?

end;

end;

функции для работы с вариантами

Существует еще ряд функций и процедур, предназначенных для работы с вариантами. Ниже приведены их определения в модуле System.

procedure VarClear(var V: Variant);

procedure VarCopy(var Dest; Variant; const Source: Variant);

procedure VarCastfvar Dest: Variant; const Source: Variant; VarType: Integer);

function VarType(const V: Variant): Integer;

function VarAsTypefconst V: Variant; VarType: Integer): Variant;

function VarIsEmpty(const V: Variant): Boolean;

function VarIsNull(const V: Variant): Boolean;

function VarToStr(const V: Variant): string;

function VarFromDateTime(DateTime: TDateTime); Variant;

function VarToDateTime(const V: Variant); TDateTime;

Процедура VarCiear() очищает вариант и помещает в поле VType значение varEmpty. Процедура VarCopy() копирует вариант Source в вариант Dest. Процедура VarCast() предназначена для преобразования варианта к некоторому типу и сохранения результата в другом варианте. Функция VarType() возвращает значение кода varXXXX для заданного варианта. Функция VarAsType() имеет то же самое назначение, что и процедура VarCastf). Функция VarIsEmpty() возвращает значение True, если поле VType варианта равно varEmpty, а функция VarIsNull() возвращает это же значение, если данное поле равно varNull. Функция VarToStr() конвертирует вариант в строку (пустую, если вариант пуст. или нулевой).

С помощью функции VarFromDateTimef) создается вариант, содержащий заданное значение типа TDateTime. Функция VarToDateTime() возвращает значение типа TDateTime, содержащееся в указанном варианте.

Тип данных OleVariant

Тип данных OleVariant практически во всем идентичен рассмотренному выше типу Variant, за одним исключением – он допускает только те типы данных, которые совместимы со средствами автоматизации OLE. В настоящее время единственное отличие проявляется при работе со строками (тип varString предназначен для строк типа AnsiString). В то время как тип Variant работает с подробными строками, при присвоении строкового значения типа AnsiString переменной типа OleVariant происходит автоматическое конвертирование этой строки в тип varOleStr и сохранение ее в варианте как тип varOleStr.

Тип данных Currency

Этот тип впервые был введен в Delphi 2 и представляет собой десятичное число с фиксированной точкой, имеющее 15 значащих цифр до десятичной точки и 4 после. Этот формат идеально подходит для финансовых вычислений, поскольку свободен от ошибок округления, свойственных операциям с плавающими числами. Настоятельно рекомендуем изменить все участвующие в финансовых расчетах переменные типов Single, Real, Double и Extended на тип Currency.

Динамические массивы

Динамические массивы – это массивы, память для которых выделяется динамически и размерность которых не известна заранее, во время компиляции. Для объявления такого массива используется обычное описание, но без указания размерности массива:

var

// Динамический массив строк

SA: array of string;

Перед использованием такого массива необходимо определить его размер с помощью процедуры SetLength(), которая выполнит распределение памяти для массива:

begin

// Выделение памяти для 33 элементов

SetLength(SA, 33);

После этого можно работать с элементами данного массива так же, как с элементами любого другого массива:

SA[0] := 'Pooh likes hunny';

OtherString := SA[0];

Динамические массивы всегда начинаются с нулевого элемента.

Для создания динамических массивов используется технология ссылок (как, например, в случае типа AnsiString). Вот маленький тест для вас: "Чему равен элемент А1[0] после выполнения приведенного ниже фрагмента?"

var

Al, A2: array of Integer;

begin

SetLength(Al, 4);

A2 := Al;

Al[0] := 1;

A2[0] ;= 26;

Правильный ответ– 26. Поскольку присвоение A2 := Al приводит к тому, что и Al и A2 ссылаются на один и тот же массив в памяти, то изменение элемента массива A2 приводит к изменению соответствующего элемента массива Al (впрочем, более точным будет утверждение, что это просто один и тот же элемент). Если же требуется создать именно копию массива, воспользуйтесь стандартной процедурой Сору():

A2 := Сору(А1);

После этого будет создана копия массива, изменения в которой не оказывают никакого влияния на данные в исходном массиве. Можно также скопировать не весь массив, а только некоторый диапазон его элементов, как показано в приведенном примере, где копируются два элемента, начиная с первого:

A2 := Сору(А1, 1, 2); // Копируются два элемента, начиная с первого

Динамические массивы могут быть многомерными. Для определения такого массива добавьте дополнительное описание array of для каждой дополнительной размерности:

var

// Двухмерный динамический массив целых чисел

 IA: array of array of Integer;

При выделении памяти для многомерного динамического массива функции SetLength() следует передать дополнительный параметр:

begin

// IA будет массивом целых чисел размерностью 5х5

SetLength(IA, 5, 5);

Обращение к элементам многомерного динамического массива ничем не отличается от обращения к элементам обычного массива:

1А[0,3] := 28;

Записи

Структуры, определяемые пользователем, в Object Pascal называются записями (record). Они эквивалентны типам данных struct в языке С или Type – в языке Visual Basic:

Object Pascal также поддерживает вариантные записи {variant records}, которые обеспечивают хранение разнотипных данных в одной и той же области памяти. Не путайте эти записи с рассмотренным выше типом Variant – вариантные записи позволяют независимо получать доступ к каждому из перекрывающихся полей данных. Если вы знакомы с языком С или С-Н-, то можете понимать вариантные записи как аналог концепции union в структурах языка С или C++. Приведенный ниже код показывает вариантную запись, в которой поля типа Double, Integer и Char занимают одну и ту же область памяти.

 type

TVariantRecord=record

NullStrField: PChar;

IntField: Integer;

case Integer of 0: (D: Double);

1: (I: Integer);

2: (С: char);

end;

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

Множества

Множества – уникальный для языка Pascal тип данных, который не имеет аналогов в языках Visual Basic, С или C++ (хотя в Borland C++ Builder реализован шаблонный класс Set, эмулирующий поведение множеств в Pascal). Множества обеспечивают эффективный способ представления коллекций чисел, символов или других перечислимых значений. Новый тип множества можно определить с помощью ключевого слова set of с указанием перечислимого типа или диапазона в некотором множестве допустимых значений:

type

TCharSet = set of char; // Допустимые элементы: #0 - #255

TEnum = (Monday, Tuesday, Wednesday, Thursday, Friday);

TEnumSet = set of TEnum; // Может содержать любую комбинацию членов

TEnum TSubrangeSet = set of 1..10; // Допустимые элементы: 1-10

TAlphaSet = set of 'A'..'z'; // Допустимые элементы: 'А' - 'г'

Заметим, что множество может содержать только до 256 элементов. Кроме того, в множествах после ключевого слова set of могут указываться только перечислимые типы данных. Таким образом, следующие объявления некорректны:

type

TintSet = set of Integer; // Слишком много элементов

TStrSet = set of string; // Неперечислимый тип данных

Внутренне элементы множеств хранятся как отдельные биты, что делает их весьма эффективными в плане скорости обработки и использования памяти. Множества, насчитывающие менее чем 32 базовых элемента, могут храниться и обрабатываться в регистрах процессора, что способствует еще большей эффективности. Множества с 32 (или более) элементами (например, множество символов char из 255 элементов) хранятся в памяти. Поэтому для достижения максимальной скорости обработки целесообразно определять множества не более чем с 32 базовыми элементами.

Использование множеств

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

type

TCharSet = set of char; // Допустимые члены: #0 - #255

TEnum = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);

TEnumSet = set of TEnum; // Может содержать любую комбинацию членов TEnum

var

CharSet: TCharSet;

EnumSet: TEnumSet;

SubrangeSet: set of 1..10; // Допустимые члены: 1-10

AlphaSet: set of 'A'..'z'; // Допустимые члены: 'А' - 'z' begin

CharSet := ['A'..'J', 'a', 'm'];

EnumSet := [Saturday, Sunday];

SubrangeSet := [1, 2, 4..6];

AlphaSet := []; // Пустое множество end;

Операторы работы с множествами

Object Pascal предоставляет несколько операторов для работы с множествами (например, для определения принадлежности к множеству, добавления или удаления элементов и пересечения множеств).

Проверка принадлежности к множеству

Оператор in используется для определения, входит ли данный элемент в состав того или иного множества. Например, следующий код используется для определения того, содержится

ли символ 'S' в множестве CharSet:

if 'S' in CharSet then // Некоторые действия;

В приведенном ниже примере осуществляется проверка отсутствия члена Monday в множестве EnumSet.

if not (Monday in EnumSet) then // Некоторые действия;

Добавление и удаление элементов множеств

Операторы + и - или процедуры Include () и Exclude () могут быть использованы для добавления или удаления элементов множеств:

Include(CharSet, 'a');            // Добавление 'а' в множество

CharSet := CharSet + ['b'];       // Добавление 'Ь' в множество

 Exclude(CharSet, 'х');            // Удаление 'х' из множества

CharSet := CharSet - ('у', '2']; // Удаление 'у' и 'z' из множества

Пересечение множеств

Оператор * используется для вычисления пересечения двух множеств. В результате операции Sell * Set2 получается множество с элементами, содержащимися в обоих множествах одновременно. Приведенный ниже код является эффективным способом определения того, содержит ли множество несколько заданных элементов.

if ['а', 'Ь', 'с'] * CharSet = ['&', 'Ь1, 'с'] then // Некоторые действия

Объекты

Объекты в Object Pascal можно представить как записи, которые помимо данных содержат функции и процедуры. Но поскольку объектная модель Delphi детально обсуждается в разделе "Использование объектов Delphi" настоящей главы, здесь мы рассмотрим только основы синтаксиса объявления объектов Object Pascal. Объект объявляется следующим образом:

Type TChildObject = class(TParentObject);

SomeVar; Integer;

procedure SomeProc;

end;

Хотя объекты Delphi не совсем идентичны объектам языка C++, это объявление очень близко к описанию, используемому в языке C++:

class TChildObject ; public TParentObject

{

int SomeVar;

void SomeProc();

};

Методы определяются так же, как и обычные процедуры и функции (о которых речь пойдет позднее, в разделе "Процедуры и функции" этой же главы). Единственное отличие– это добавление имени объекта и точки перед именем метода:

procedure TChildObject.SomeProc;

begin

{ код процедуры } end;

Символ точки в Object Pascal no своей функциональности похож на оператор "." в языке Visual Basic или на оператор "::" в языке C++. Следует отметить, что, хотя все три языка позволяют использовать классы, только Object Pascal и C++ позволяют создавать новые классы, полностью соответствующие парадигме объектно-ориентированного программирования.

Указатели

Указатель (pointer) представляет собой переменную, содержащую местоположение (адрес) ячейки памяти. С примером указателя мы уже сталкивались в этой главе, когда рассматривали тип PChar. Общий тип указателя в Object Pascal имеет название Pointer – нетипизированный указатель, который содержит адрес некоего места в памяти, при этом компилятору ничего не известно о данных, располагающихся по этому адресу. Однако применение таких "указателей вообще" противоречит концепции строгого контроля типов, а потому вам в основном придется иметь дело с типизированными указателями, т.е. с указателями на данные конкретного типа.

 На заметку Указатели– тема достаточно сложная для новичка, и можно писать приложения Delphi, не будучи досконально с ней знакомым, Однако, по мере ее освоения указатели могут стать одним из самых мощных инструментов программирования, доступных в Delphi,

Типизированные указатели объявляются в разделе Type программы с использованием символа " (или ключевого слова Pointer) – оператора указателя. Типизированные указатели позволяют компилятору отслеживать, с какими данными вы работаете и не выполняете ли вы над ними некорректные действия. Вот примеры объявлений типизированных указателей:

Type

Pint = integer;   // Pint - указатель на Integer

Foo = record       // Тип - запись

GobbledyGook: string;

Snarf: Real;

end;

PFoo = ^oo;        // PFoo - указатель на объект типа foo var

P: Pointer;         // Нетипизированный указатель

P2: PFoo;           // Указатель на экземпляр Foo

На заметку Программисты на языке C++ могут заметить схожесть оператора ^ Object Pascal и оператора * языка C++. Тип Pointer в Object Pascal соответствует типу void * в языке С.

Запомните, что переменная типа Pointer всегда содержит только адрес памяти. О выделении памяти для той структуры, на которую будет указывать указатель, должен позаботиться сам программист (для этого можно воспользоваться одной из функций, перечисленных в табл. 2.6).

На заметку Когда указатель не указывает ни на какое место в памяти, его значение равно 0. При этом говорят, что его значение равно Nil, а сам указатель – нулевой.

Получить доступ к данным, на которые указатель указывает, можно с помощью оператора ^, следующего за именем этой переменной. Этот метод называется "разрешением указателя". Ниже приведен пример работы с указателями.

Program PtrTest;

Type

MyRec = record

I: Integer;

S: string;

R: Real;

end;

PHyRec = ^Myrec;

var Rec : PMyRec;

begin New(Rec);      // Выделяем память для новой записи Rec

Rec\I := 10; // Помещаем в нее некоторые данные

// Обратите внимание на оператор ^

Rec\S := 'Теперь помещаем в нее данные другого типа'; 

Rec'.R ;= 6.384;

{ Запись Rec заполнена } Dispose(Rec); // Не забывайте освобождать память!

end.

Когда следует использовать функцию New()       

Функция New() используется при выделении памяти для указателя на структуру данных известного размера. Так как компилятору известен размер структуры, для которой требуется выделить память при выполнении функции New () будет распределено требуемое количество байтов, причем такой способ выделения более корректен и безопасен, чем вызов функции GetMem() или AllocMem() В тоже время никогда не используйте функцию New() для выделения памяти для типов Pointer или PChar так как в этом случае компилятору не известно, какое количество памяти должно быть выделено И не забывайте использовать функцию Dispose () для освобождения памяти выделенной с помощью функции New()

Для выделения памяти структурам размер которых на этапе компиляции еще не известен используются функции GetMein() и AllocMem() Например компилятор не может определить заранее сколько памяти потребуется выделить для структур задаваемых переменными типа PChar или Pointer что связано с самой природой этого типа данных Самое важное – не пытаться манипулировать количеством памяти, большим чем было выделено реально поскольку наиболее вероятным результатом таких действий будет ошибка доступа к памяти (Access Violation) Для освобождения памяти выделенной с помощью упомянутых выше функции используйте функцию FreeMem() Кстати, для распределения памяти лучше пользоваться функцией АПосМет() так как она всегда инициализирует выделенную память нулевыми значениями

Один из аспектов работы с указателями в Object Pascal, который существенно отличается от работы (, ними в языке С – это их строжайшая типизация Так, в приведенном ниже примере переменные а и Ь несовместимы по типу

var

a: ^Integer;

b: ^Integer;

В то же время в эквивалентном описании на языке С эти переменные вполне совместимы по типу

int *a;

int *b;

Object Pascal создает уникальный тип для каждого объявления указателя на тип, поэтому для совместимости по типу следует объявить не только переменные, но и их тип

type Рtrlnteger = ^Integer; // Создаем тип данных

var а, b: Ptrlnteger;       // Теперь а и b совместимы по типу

Псевдонимы типов

Object Pascal позволяет давать новые имена уже имеющимся типам – создавать и\ псевдонимы (aliases) Так, если потребуется присвоить новое имя MyReallyNiftyInteger обычному типу Integer, можно использовать такой код

type MyReallyNiftyInteger = Integer;

Новый тип совместим с оригиналом Это означает, что везде, где вы использовали Integer вы можете применять MyReallyNiftyInteger

Но можно создать и строго типизированный псевдоним (т.е псевдоним, не совместимый с оригиналом) Для этого используется дополнительное ключевое слово type

type МyOtherNeatInteger = type Integer;

При этом новый тип будет преобразовываться в оригинальный при таких операциях, как, например присвоение, однако как параметр он будет несовместим с оригиналом Следующий код синтаксически корректен

var

MONI: MyOtherNeatInteger;

I: Integer;

begin

I ;= 1;

MONI ;= I;

Однако пример приведенный ниже, вызовет появление ошибки несовместимости типов:

procedure Goon(var Value: Integer);

begin

// некий программный текст end;

var

M; MyOtherNeatInteger;

begin

M := 29;

Goon(M); // Ошибка: тип переменной M не совместим с Integer

   Помимо усиленного контроля за совместимостью типа данных для строго типизированных псевдонимов компилятор также генерирует информацию о типе во время выполнения программы.

Приведение и преобразование типов

Приведение типов – это технология, посредством которой компилятор можно заставить рассматривать переменную одного типа, как переменную некоторого другого типа. Pascal является строго типизированным языком, который весьма требователен в отношении соответствия типов формальных параметров функции и реальных параметров, задаваемых при ее вызове. Поэтому в некоторых случаях переменную одного типа необходимо привести к некоторому другому типу, чтобы требования компилятора были удовлетворены. Предположим, необходимо присвоить символьное значение переменной типа byte:

var

с: char;

b: byte;

begin

 c:=' s ';

b := с;   // Для этой строки компилятор выдаст сообщение об ошибке

end.

В приведенном выше примере необходимо преобразовать переменную с к типу byte. Фактически, выполнение приведения типа явно указывает компилятору, что программист точно знает, что он делает, требуя преобразовать один тип данных в другой:

var

с: char;

b: byte;

begin

с := 's';

b := byte(с); // Теперь компилятор не обнаружит ошибки в этой строке end.

Object Pascal также предоставляет очень широкие возможности по приведению типов между объектами с использованием оператора as. Подробно эти возможности описаны ниже, в разделе "Информация о типе времени выполнения" настоящей главы.

Строковые ресурсы

В Delphi 3 появилась возможность внесения строковых ресурсов непосредственно в исходный код языка Object Pascal, для чего используется выражение resourcestring. Строковые ресурсы представляют собой литеральные строки (обычно это – сообщения программы пользователю), которые физически расположены в присоединенных к приложению или библиотеке ресурсах, а не внедрены в исходный текст программы. В частности, подобное отделение строк от исходного кода упрощает перевод приложения на другой язык – для этого достаточно просто присоединить к приложению строковые ресурсы на необходимом языке без ретрансляции самого приложения. Строковые ресурсы описываются в виде пар значений

идентификатор = строковый литерал, как показано ниже.

resourcestring ResString1 = 'Resource string 1';

ResString2 = 'Resource string 2';

ResString3 = 'Resource string 3';

В программе строковые ресурсы используются так же, как и обычные строковые константы:

resourcestring ResStringI = 'hello';

ResString2 = 'world';

var Stringi: string;

begin Stringi := ResString1 + ' ' + ResString2;

end;

Использование открытых массивов

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

function AddEmUp(A: array of Integer): Integer:

В открытом массиве можно передавать переменные, константы или выражения из констант. Ниже приведен пример, который демонстрирует вызов функции AddEmUp() с передачей ей нескольких различных элементов.

var

i, Re2: Integer;

const

j = 23;

begin

i := 8;

Rez := AddEmUp([i, 50, j, 89]);

Для получения информации о фактически передаваемом массиве параметров в функции или процедуре могут использоваться функции High(), Low() и Size0f(). Для иллюстрации их использования ниже приведен текст функции AddEmUp(), которая возвращает сумму всех переданных ей элементов массива А.

function AddEmUp(A: array of Integer): Integer;

var

i: Integer;

begin

Result := 0;

for i := Low(A) to High(A) do inc(Result, A[i]);

end;

Object Pascal также поддерживает тип array of const. который позволяет передавать в одном массиве данные различных типов. Синтаксис объявления функций или процедур, использующих такой массив дня получения параметров, следующий:

procedure whatHaveIGot(A: array of const);

Вызвать объявленную выше функцию можно, например, с помощью такого оператора:

WhatHaveIGot(['Tabasco', 90, 5.6, @WhatHaveIGot, 3.14159, True, 's']);

При передаче функции или процедуре массива констант все передаваемые параметры компилятор неявно конвертирует в тип TVarRec. Тип данных TVarRec объявлен в модуле System следующим образом:

type PVarRec = TVarRec;

TVarRec = record case Byte of

vtlnteger:    (VInteger: Integer; VType: Byte);

vtBoolean:    (VBoolean: Boolean);

vtChar:       (VChar: Char);

vtExtended:   (VExtended: PExtended);

vtString:     (VString: PShortString);

vtPointer:    (VPointer: Pointer);

vtPChar:      (VPChar: PChar);

vtObject:     (VObject: TObject);

vtClass:      (VClass: TClass);

vtWideChar:   (VWideChar: WideChar);

vtPWideChar: (VPWideChar; PWideChar);

vtAnsiString: (VAnsiString: Pointer);

vtCurrency:   (VCurrency: PCurrency);

vtVariant:    (Wariant; PVariant);

vtlnterface: (VInterface; Pointer);

vtWideString: (VWideString: Pointer);

vtlnt64:      (VInt64: PInt64);

end;

Поле VType определяет тип содержащихся в данном экземпляре записи TVarRec данных и

может принимать одно из приведенных ниже значений.

const

{ значения поля TVarRec.VType } vtlnteger    =0;

vtBoolean    = 1;

vtChar       = 2;

vtExtended   =3;

vtString     = 4;

vtPointer    = 5;

vtPChar      = 6;

vtObject     = 7;

vtClass      = 8;

vtWideChar   = 9;

vtPWideChar = 10;

vtAnsiString = 11;

vtCurrency   = 12;

vtVariant    = 13;

vtlnterface = 14;

vtWideString = 15;

vtlnt64      = 16;

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

procedure WnatHaveIGot(A: array of const);

var

i: Integer;

TypeStr: string;

begin

for i := low(A) to High(A) do begin

case A[i].VType of vtlnteger    ;

TypeStr := 'Integer';

vtBoolean    : TypeStr := 'Boolean';

vtChar       : TypeStr := 'Char';

vtExtended   : TypeStr := 'Extended';

vtString     : TypeStr := 'String';

vtPointer      TypeStr = 'Pointer';

vtPChar        TypeStr = 'PChar';

vtObject       TypeStr = 'Object';

vtClass        TypeStr = 'Class';

vtWideChar     TypeStr = 'WideChar';

vtPWideChar    TypeStr = 'PWideChar';

vtAnsiString   TypeStr = 'AnsiString';

vtCurrency     TypeStr = 'Currency';

vtVariant      TypeStr = 'Variant';

vtlnterface    TypeStr = 'Interface';

vtWideString   TypeStr = 'WideString';

vtlnt64        TypeStr = 'Int64';

end;

ShowMessage(Format('Array item %d is a %s', [i, TypeStr]));

end;

end;

Пакеты

Пакеты (packages) Delphi позволяют размещать части некоторого приложения в различных модулях, которые затем могут совместно использоваться несколькими приложениями. Для разработок, выполненных в среде Delphi 1 и 2. преимуществами использования пакетов можно воспользоваться без внесения каких-либо изменений в существующие исходные тексты программ.

Пакеты можно понимать как коллекции модулей, сохраняемых в отдельных файлах-библиотеках (Borland Package Library, BPL), подобных DLL-файлам. Приложение можно связать с пакетированными модулями непосредственно во время выполнения, а не при его трансляции. Естественно, при этом размер выполняемого файла уменьшается, так как часть кода и данных располагается в BPL-файле. Delphi позволяет создавать пакеты четырех типов.

1. Исполнимый пакет. Этот тип пакетов содержит модули, используемые программой во время ее выполнения. Скомпилированное для работы с некоторым пакетом, приложение не будет работать при его отсутствии. Примером пакета такого типа может служить пакет Delphi VCL50.BPL.

2. Конструкторский пакет. Пакет этого типа содержит элементы, необходимые для конструирования приложения (например, компоненты, редакторы свойств и компонентов, программы-эксперты). Эти пакеты могут быть включены в библиотеку компонентов Delphi с помощью команды Component^ Install Package. В качестве примера можно привести пакет Delphi DCL*.BPL. Подробно пакеты этого типа описываются в главе 21 второго тома, "Создание пользовательских компонентов в Delphi".

3. Исполнимые и конструкторские пакеты. Такие пакеты применяются как пакеты одновременно обоих указанных выше типов. Использование подобных пакетов упрощает создание и распространение приложения. Однако это тип пакетов менее эффективен, поскольку помимо необходимой для работы исполняемой части они содержат также конструкторскую поддержку.

4. Пакеты, не относящиеся ни к одному из перечисленных типов. Такие пакеты могут применяться только другими пакетами и не используются непосредственно приложением или средой конструирования.

Использование пакетов Delphi

Создание приложений, работающих с пакетами Delphi, представляет собой несложную задачу. Для этого достаточно установить флажок опции Build with Runtime Packages во вкладке Packages диалогового окно Project Options. Эта опция требует от компилятора создания приложения, динамически скомпонованного с исполнимыми пакетами, вместо статической компоновки всех модулей в общий ЕХЕ- или DLL-файл. В результате размер файла приложения станет намного меньше. Однако не забывайте, что в этом случае при распространении приложение потребуется дополнить необходимыми пакетами.

Синтаксис описания пакетов

Чаще всего пакеты создаются с помощью редактора Package Editor, который вызывается командой File^Newo Package. Этот редактор генерирует исходный файл Delphi Package Source (DPK), который затем компилируется в пакет. Синтаксис, используемый при создании DPK-файла, очень прост и имеет следующий формат:

package Иля пакета

requires Package1, Package2, ...;

contains

Unit1 in Unit1.pas, Unlt2 in Unit2.pas,

end.

Пакеты, перечисленные в предложении requires, необходимы для работы текущего пакета. Обычно эти пакеты содержит модули, используемые теми модулями, которые перечислены в предложении contains (последние будут скомпилированы в данный пакет). При этом следует помнить, что модули, перечисленные в предложении contains этого пакета, не должны упоминаться в предложениях contains пакетов, перечисленных в предложении requires данного модуля. Заметим также, что в пакет будет неявно включен любой модуль, используемый другим модулем, указанным в предложении contains пакета (если только он уже не содержится в одном из пакетов, указанных в предложении requires).


 

А также другие работы, которые могут Вас заинтересовать

13546. «Ибо что пользы человеку приобрести весь мир, а себя самого погубить и повредить себе» (Книга Екклесиаста) 33 KB
  Ибо что пользы человеку приобрести весь мир а себя самого погубить и повредить себе Книга Екклесиаста Выбранное мною высказывание затрагивает вопрос о влиянии материального благосостояния материальных ценностей на духовное развитие человека духовные ценнос
13547. Истина 16.86 KB
  Всякая истина рождается как ересь и умирает как предрассудок. Томас Генри Гексли В выбранном мною высказывании автор затрагивает проблему эволюции человеческого познания как процесса бесконечного продвижения от одной относительной истины до другой. Во все времен
13548. Философия: «Цивилизация шла и шла и зашла в тупик. Дальше некуда. Все обещали, что наука и цивилизация выведут нас. Но теперь уже видно, что никуда не выведут; надо начинать новое» Л. Н. Толстой 22.02 KB
  Философия: Цивилизация шла и шла и зашла в тупик. Дальше некуда. Все обещали что наука и цивилизация выведут нас. Но теперь уже видно что никуда не выведут; надо начинать новое Л. Н. Толстой. Выбранное мною высказывание посвящено осмыслению сущности направленности обще...
13549. Единственная проблема современности заключается в том, сумеет ли человек пережить свои собственные изобретения 15.12 KB
  Единственная проблема современности заключается в том сумеет ли человек пережить свои собственные изобретения. Л. де Бройль Выбранное мною высказывание связано с проблемой того насколько научный прогресс сочетается с моралью и нравственностью. Развиваясь челове...
13550. Прогресс – стремление к возведению человека в человеческий сан 16.68 KB
  Прогресс – стремление к возведению человека в человеческий сан. Н. Г. Чернышевский Выбранное мной высказывание связано с проблемой нравственной стороны общественного прогресса. Я считаю эту проблему актуальной во все времена так как зачастую сосредотачивая вним...
13551. Школа – это мастерская, где формируется мысль подрастающего поколения, надо крепко держать ее в руках, если не хочешь выпустить из рук будущее 14.22 KB
  Школа – это мастерская где формируется мысль подрастающего поколения надо крепко держать ее в руках если не хочешь выпустить из рук будущее. А.Барбюс Выбранное мною высказывание связано с проблемой образования его важности для будущего всего общества. Издревле лю...
13552. Если мы хотим идти вперед, то одна нога должна остаться на месте, в то время как другая делает следующий шаг 15.76 KB
  Если мы хотим идти вперед то одна нога должна остаться на месте в то время как другая делает следующий шаг. Это – первый закон всякого прогресса одинаково применимый как к целым народам так и к отдельным людям. И. Этвеш В выбранном мною высказывании явно представле
13553. Знание – не инертный, пассивный посетитель, приходящий к нам, хотим мы этого или нет; его нужно искать, прежде, чем оно будет нашим, оно – результат большой работы и потому – большой жертвы 14.88 KB
  Знание – не инертный пассивный посетитель приходящий к нам хотим мы этого или нет; его нужно искать прежде чем оно будет нашим оно – результат большой работы и потому – большой жертвы. Г.Бокль В выбранном мною высказывании автор поднимает проблему познания способ
13554. Разумный человек приспосабливается к миру; неразумный – упорно пытается приспособить мир к себе. Поэтому прогресс зависит от неразумных людей 28 KB
  Разумный человек приспосабливается к миру; неразумный – упорно пытается приспособить мир к себе. Поэтому прогресс зависит от неразумных людей. Бернард Шоу Выбранное мною высказывание затрагивает проблему движущих сил прогресса. Данная тема крайне актуальная в со