Главная » Delphi » Пользовательские типы данных Delphi

0

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

Массивы

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

var

A: Array[0..7] of Integer;Этот оператор эквивалентен следующему объявлению в языке  C:

int A[8];

Соответствующий оператор языка Visual Basic выглядит таким образом:

Dim A(8) as Integer

Массивы  Object  Pascal  имеют  одно  существенное отличие от  массивов языков C или Visual Basic (и многих  других языков) — они не обязаны начинаться с определенно го номера элемента. Например, можно  определить массив  из трех  элементов, начи нающийся с элемента под номером 28:

var

A: Array[28..30] of Integer;

Поскольку в Object  Pascal элементы массива не обязательно начинаются с нулевого или  первого элемента, следует  принимать необходимые меры  при  организации ите раций, например в цикле  for. Для этого  компилятор предоставляет две встроенные функции — High() и Low(), возвращающие верхнюю и нижнюю границы заданного массива.  Программа станет более  устойчивой к ошибкам и возможным изменениям в описании массива,  если в ней будут использоваться эти функции. Например:

var

A: array[28..30] of Integer;

i: Integer;

begin

for i := Low(A) to High(A) do      // Не используйте для цикла

A[i] := i;                         // жесткий код!

end;

CОВЕТ

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

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

стве разграничителя списка размерностей:

var

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

A: array[1..2, 1..2] of Integer;

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

рез запятую:

I := A[1, 2];

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

Динамический массив (dynamic array) — это массив,  память  для которых выделяется динамически. Размерность динамического массива на момент компиляции не извест на. Для объявления такого  массива  применяется обычное описание, но без указания размерности:

var

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

SA: array of string;

Перед  использованием  динамического  массива   следует   с  помощью  процедуры

SetLength() определить его размер, что приведет к выделению необходимой памяти:

begin

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

SetLength(SA, 33);

После этого с элементами динамического массива можно работать как с элемента

ми любого другого массива:

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

НА ЗАМЕТКУ

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

Динамические массивы — это тип данных с управляемым временем жизни, поэтому можно не заботиться о своевременном освобождении выделенной им памяти. Она бу- дет освобождена автоматически, когда данная переменная покинет область видимо- сти. Но это не означает, что при необходимости память нельзя освободить самостоя- тельно (например, если массив использовал слишком большое ее количество). Для этого достаточно просто присвоить массиву значение nil:

SA := nil; // Освобождение памяти, выделенной массиву SA

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

var

A1, A2: array of Integer;

begin

SetLength(A1, 4);

A2 := A1;

A1[0] := 1;

A2[0] := 26;

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

A2 := Copy(A1);

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

мента, начиная с первого:

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

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

var

// Двумерный динамический массив целых чисел: IA: array of array of Integer;

При   выделении  памяти  для   многомерного  динамического  массива   функции

SetLength() следует передать дополнительный параметр:

begin

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

SetLength(IA, 5, 5);

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

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

IA[0,3] := 28;

Записи

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

{ Pascal } Type

MyRec = record

i: Integer;

d: Double;

end;

/* C */

typedef struct {

int i;

double d;

} MyRec;

‘Visual Basic

Type MyRec

i As Integer

d As Double

End Type

При  работе с записями доступ  к их  полям  можно  получить с помощью символа точки  (точечный оператор):

var

N: MyRec;begin

N.i := 23;

N.d := 3.4;

end;

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

type

TVariantRecord = record

NullStrField: PChar;

IntField: Integer;

case Integer of

0: (D: Double);

1: (I: Integer);

2: (C: char);

end;

НА ЗАМЕТКУ

Правила Object Pascal запрещают размещать в вариантной части записи какие-либо типы данных с управляемым временем жизни.

Вот эквивалент приведенного кода в языке  C++:

struct TUnionStruct

{

char * StrField; int IntField; union u

{

double D; int i; char c;

};

};

Множества

Множества (sets) —  уникальный для  языка  Pascal  тип  данных, который не  имеет аналогов в языках  Visual Basic, C или 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'; // Допустимы элементы: ‘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'; // Допустимы элементы: ‘A’ – ‘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() могут быть использова

ны для добавления (union) или удаления  (difference) элементов множеств:

Include(CharSet, ‘a’);             // добавить ‘a’ в множество CharSet := CharSet + [‘b’]; // добавить ‘b’ в множество Exclude(CharSet, ‘x’);   // удалить ‘z’ из множества CharSet := CharSet – [‘y’, ‘z’]; // удалить ‘y’ и ‘z’ из множества

CОВЕТ

Везде, где только это возможно, для добавления или удаления элементов из множест- ва вместо операторов + и – используйте процедуры Include() и Exclude(). Каждая из этих процедур реализуется одной машинной командой, в то время как для реализа- ции операторов + и – требуется по 13+6n команд (здесь n — количество битов в мно- жестве).

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

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

if [‘a’, ‘b’, ‘c’] * CharSet = [‘a’, ‘b’, ‘c’] then

// выполнить действия

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии