case <поле_N>: <порядковоый_тип_данных> of
значение_1: (вариант 1);
...
значение_M: (вариант 2);
end;
Отличительная особенность записи с вариантным полем – наличие внутри нее оператора-селектора case. Если этот оператор вам пока незнаком, то отложите рассмотрение этой части материала и вернитесь к ней после того, как прочтете раздел «Операторы», а для всех остальных я продолжу.
Допустим, что мы пишем программу для владельца гостиницы, с помощью которой он собирается вести учет своих постояльцев. Владельцу нужны следующие данные: фамилия (Surname) и имя (FName) постояльца, а также даты въезда (EntryDate) и выезда (ExitDate). Немного подумав, наш привередливый заказчик потребовал, чтобы при заказе номера люкс (VIPRoom) наша программа учитывала домашний адрес постояльца, а для обычных посетителей достаточно запомнить только номер паспорта (Doc). В такой ситуации к концу бессонной ночи мы бы изобрели запись THotelGuest.
Type
THotelGuest = record
SurName, FName : string[30];
EntryDate, ExitDate: TDate;
case VIPRooms: Boolean of //селектор проверяет значение поля VIPRooms
False: (Doc: string[15]); //False – только номер паспорта
True: (City, Street : string[20]; //True – домашний адрес
HomeNum: smallint);
end;
Оператор case проверяет поле VIPRooms и в зависимости от принимаемого им значения предоставляет для заполнения те или иные данные. Такой подход позволяет значительно рациональнее использовать оперативную память компьютера.
Множества
Множества представляют собой коллекцию однотипных значений. При определении множества можно указать диапазон значений:
type TIntSet = set of 1..10;
В качестве элементов множества могут использоваться любые порядковые
типы данных:
type TCharSet = set of 'A'.. 'Z';
Кроме того, вы имеете право определять собственные элементы множества:
type TWeekDays = set of (Mo, Tu, We, Th, Fr, St, Su);
Нетерпеливый читатель спросит: «Так чем же отличаются множества от изученных ранее поддиапазонов?» Постараюсь объяснить на небольшом примере. Представьте себе, что вы работаете в театре, правда, пока не главным режиссером, а лишь осветителем. Поскольку театр небольшой, то в распоряжении осветителя лишь три прожектора:
type TLampsSet = set of (Lamp1, Lamp2, Lamp3);
Для освещения сцены осветитель может зажечь один, два или все три прожектора, т. е. выбрать любую понравившуюся комбинацию. Если ассоциировать прожекторы с ячейками памяти компьютера, то это всего-навсего три бита. Единица в ячейке свидетельствует о включении, а ноль – о выключении соответствующего прожектора (рис. 1.2).
Если множество содержит всего три элемента, то общее количество возможных комбинаций составляет 23 = 8. Зарезервированное слово set способно определять множество размерностью до 256 элементов, т. е. 2256 = 1,1579208923731619542357098500869e+77 вариантов. На практике такое количество вариантов никогда не понадобится. В частности, разработчики Delphi рекомендуют использовать множество с количеством элементов не более 16.
А теперь рассмотрим несколько строк кода, демонстрирующих работу с множествами:
type TLampsSet = set of (Lamp1, Lamp2, Lamp3);
var LampsSet : TLampsSet;
Begin
LampsSet:=[]; //0,0,0 - полностью очистили множество
LampsSet:=[Lamp1]; //1,0,0 - включили первый элемент
LampsSet:=LampsSet+[Lamp3]; //1,0,1 - добавили третий элемент
LampsSet:=LampsSet-[Lamp1]; //0,0,1 - отключили первый элемент
LampsSet:=[Lamp1,Lamp2,Lamp3]; //1,1,1 – включили все три элемента
End.
Если определено два однотипных множества, то между ними вполне допустимы операции сложения, вычитания, умножения и сравнения (<=, >=, =, <>).
В операциях сравнения множество X меньше или равно множеству Y (выражение (X <= Y) = True), если каждый элемент множества X является членоммножества Y. Множество X равно множеству Y (выражение (X = Y) = True), ес-
ли все элементы множества X точно соответствуют элементам Y. Множество X не равно множеству Y (выражение (X <> Y) = True), если хотя бы один элемент множества X отсутствует в множестве Y.
Для того чтобы проверить, включен ли элемент в множество, применяютоператор in.
if (Lamp2 in LampsSet) then <операция 1> else <операция 2>;
Указатели
А теперь поговорим об указателях. Начнем с напоминания о том, что физчески любая переменная представляет собой не что иное, как область памяти, содержащую какие-то данные. Когда мы объявим переменную MyValue : integer, в памяти компьютера для хранения значения этой переменной будет зарезервировано 4 байта. Содержимое переменной MyValue можно просмотреть непосредственно в этой области памяти. Объявив другую переменную, мы заставим операционную систему отвести под эту переменную новые свободные ячейки памяти. При этом значения указателей на MyValue и новуюпеременную будут различны.
Указатель представляет собой переменную, содержащую адрес области памяти. Повторюсь еще раз, т. к. это важно: указатель хранит не содержимое памяти, а адрес ячеек памяти. Поэтому он сам не занимает никакого места, кроме того, которое нужно для хранящегося в нем адреса. На практике это может выглядеть следующим образом:
var MyValue : integer;
pMyValue : pointer;
Begin
MyValue:=100;
pMyValue:=@MyValue; // указателю присвоен адрес переменной MyValue
end;
Обратите внимание, что в операции присваивания адреса указателю перед названием переменной помещен символ @. Допустим, у нас есть переменная See : Integer и мы хотим через указатель передать ей данные из переменной MyValue. Тогда, дабы увидеть данные, хранящиеся в MyValue(), воспользуемся следующими строками кода:
See:=INTEGER(pmyValue^);
Тип данных Pointer называют нетипизированным указателем, т. к. он может указывать на переменную любого типа. Чаще применяют так называемые типизированные указатели, которые способны работать с переменными определенного типа. Объявление такого указателя выглядит следующим образом:
var pInt:^integer;
Рассмотрим еще один небольшой пример:
var pInt : ^integer;
MyValue : integer;
begin
MyValue:=100; //целочисленной переменной присвоено значение 100
Pint :=Addr(MyValue); //указатель установлен в область памяти, где хранится MyValue
pInt^ :=123; //в область памяти записано значение 123
end;
Результатом данного упражнения стало изменение значения переменной MyValue без обращения к ней.
Тип PChar
Это типизированный указатель на строки, завершающиеся нулем (null-terminated strings). Дело в различии между форматом строк, используемых в функциях Windows API, и строками языка Object Pascal. Строки Windows и языка С не имеют определенного размера, и признаком их окончания служит нулевой символ (#0). При необходимости использовать встроенные функции Windows вам придется использовать PChar.
Помимо PChar в Object Pascal объявлены еще два типа указателей, специализирующихся на работе с текстовыми строками, заканчивающимися нулем. Это указатели PAnsiChar и PWideChar. Указатель PAnsiChar предназначен для работы со строками Ansi, а PWideChar – указатель на строку с 16-битными символами из таблицы Unicode.
var Buff : Array[0..12] of Char = 'Hello world!'#0;
P : PChar;
Begin
p:=@Buff[0];
p:='Hello world!';
end;
В этом примере продемонстрированы способы сопоставления текстовых данных с указателем PChar.
Вариантные типы
Универсальный тип данных. В основном он предназначен для работы с результатами заранее не известного типа. Но за универсальность приходится платить: на переменную вариантного типа дополнительно отводится еще два байта памяти (это не считая байт, необходимых для хранения обычной типизированной переменной).
var vUniverse : variant;
iInt : integer;
sStr : string;
rR : real;
Begin
iInt:=1; sStr:='Привет'; rR:=1.987;
vUniverse:=iInt; vUniverse:=sStr; vUniverse:=rR;
end;
Ни один из типов данных не позволит таких вольностей, как variant. В приведенном примере переменной vUniverse по очереди присваиваются значения различного типа.
Вариантный тип переменной полезен при вызове объектов, поддерживающих технологию OLE Automation, хранения значений даты/времени и создания массивов переменной длины.
Дата добавления: 2016-03-15; просмотров: 1719;