Глава 4. Типы

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

                        ----------------   ----   ------   ----
            описание -->¦ идентификатор +-->¦ = +-->¦ тип +-->¦ ; +-->
              типа      L----------------   L----   L------   L----

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

                                ---------------------
            тип   --------T---->¦     простой тип    ¦--------->
                          ¦     L---------------------    ^
                          ¦     ---------------------    ¦
                          +---->¦   строковый тип    +----+
                          ¦     L---------------------    ¦
                          ¦     ---------------------    ¦
                          +---->¦   ссылочный тип    +----+
                          ¦     L---------------------    ¦
                          ¦     ---------------------    ¦
                          +---->¦   структурный тип  +----+
                          ¦     L---------------------    ¦
                          ¦     ---------------------    ¦
                          +---->¦   процедурный тип  +----+
                          ¦     L---------------------    ¦
                          ¦     ---------------------    ¦
                          L---->¦ идентификатор типа +-----
                                L---------------------

             Имеется пять следующих основных классов типов.  Они описыва-
        ются в следующем разделе.



Простые типы

Простые типы определяют упорядоченные множества значений. -------------------- простой тип -----T---->¦ порядковый тип +---------> ¦ L-------------------- ^ ¦ -------------------- ¦ L---->¦ вещественный тип +------ L-------------------- --------------------- вещественный тип ----->¦ идентификатор +-----> ¦ вещественного типа ¦ L--------------------- Идентификатор вещественного типа относится к числу стандарт- ных идентификаторов, которые могут быть вещественными, с одинар- ной точностью, с двойной точностью, с повышенной точностью и сложными. Примечание: В разделах "Числа" и "Строковые константы" Главы 2 вы можете найти описание того, как обозначать конс- танты целого и вещественного типов.

Порядковые типы

Порядковые типы представляют собой подмножество простых ти- пов. Все простые типы, отличные от вещественных типов, являются порядковыми и выделяются по следующим четырем характеристикам. - Все возможные значения данного порядкового типа представ- ляют собой упорядоченное множество, и каждое возможное значение связано с порядковым номером, который представ- ляет собой целочисленное значение. За исключением значе- ний целочисленного типа, первое значение любого порядко- вого типа имеет порядковый номер 0, следующее значение имеет порядковый номер 1 и так далее для каждого значения в этом порядковом типе. Порядковым номером значения цело- численного типа является само это значение. В любом по- рядковом типе каждому значению, кроме первого, предшест- вует другое значение, и после каждого значения, кроме последнего, следует другое значение в соответствии с упо- рядоченностью типа. - К любому значению порядкового типа можно применить стан- дартную функцию Ord, возвращающую порядковый номер этого значения. - К любому значению порядкового типа можно применить стан- дартную функцию Pred, возвращающую предшествующее этому значению значение. Если эта функция применяется к первому значению в этом порядковом типе, то выдается сообщение об ошибке. - К любому значению порядкового типа можно применить стан- дартную функцию Succ, возвращающую следующее за этим зна- чением значение. Если эта функция применяется к последне- му значению в этом порядковом типе, то выдается сообщение об ошибке. - К любому значению порядкового типа и к ссылке на перемен- ную порядкового типа можно применить стандартную функцию Low, возвращающую наименьшее значение в диапазоне данного порядкового типа. - К любому значению порядкового типа и к ссылке на перемен- ную порядкового типа можно применить стандартную функцию High, возвращающую наибольшее значение в диапазоне данно- го порядкового типа. Синтаксис порядкового типа имеет следующий вид: --------------------- порядковый -----T---->¦ отрезок типа +---------> тип ¦ L--------------------- ^ ¦ --------------------- ¦ +---->¦ перечислимый тип +-----+ ¦ L--------------------- ¦ ¦ --------------------- ¦ L---->¦ идентификатор +------ ¦ порядкового типа ¦ L--------------------- Borland Pascal имеет 10 встроенных порядковых типов: Integer (целое), Shortint (короткое целое), Longint (длинное целое), Byte (длиной в байт), Word (длиной в слово), Boolean (булевское), ByteBool (булевское размером в байт), WordBool (булевское разме- ром в слово), LongBool (длинный булевский тип) и Char (символьный тип). Кроме того, имеется два других класса определяемых пользо- вателем порядковых типов: перечислимые типы и отрезки типов (под- диапазоны).

Целочисленные типы

В Borland Pascal имеется пять предопределенных целочисленных типов: Shortint (короткое целое), Integer (целое), Longint (длин- ное целое), Byte (длиной в байт) и Word (длиной в слово). Каждый тип обозначает определенное подмножество целых чисел, как это по- казано в следующей таблице. Предопределенные целочисленные типы Таблица 4.1 ---------------------T--------------------T--------------------- ¦ Тип ¦ Диапазон ¦ Формат ¦ +--------------------+--------------------+---------------------+ ¦ короткое целое ¦ -128 .. 127 ¦ 8 бит со знаком ¦ ¦ (Shortint) ¦ ¦ ¦ +--------------------+--------------------+---------------------+ ¦ целое ¦ -32768 .. 32767 ¦ 16 бит со знаком ¦ ¦ (Integer) ¦ ¦ ¦ +--------------------+--------------------+---------------------+ ¦ длинное целое ¦ -2147483648 .. ¦ 32 бита со знаком ¦ ¦ (Longint) ¦ ..2147483647 ¦ ¦ +--------------------+--------------------+---------------------+ ¦ длиной в байт ¦ 0 .. 255 ¦ 8 бит без знака ¦ ¦ (Byte) ¦ ¦ ¦ +--------------------+--------------------+---------------------+ ¦ длиной в слово ¦ 0 .. 65535 ¦ 16 бит без знака ¦ ¦ (Word) ¦ ¦ ¦ L--------------------+--------------------+---------------------- Арифметические действия над операндами целочисленного типа предполагают 8-битовую, 16-битовую и 32-битовую точность в соот- ветствии со следующими правилами: - Тип целой константы представляет собой встроенный целочис- ленный тип с наименьшим диапазоном, включающим значение этой целой константы. - В случае бинарной операции (операции, использующей два операнда), оба операнда преобразуются к их общему типу пе- ред тем, как над ними совершается действие. Общим типом является встроенный целочисленный тип с наименьшим диапа- зоном, включающим все возможные значения обоих типов. Нап- ример, общим типом для целого и целого длиной в байт явля- ется целое, а общим типом для целого и целого длиной в слово является длинное целое. Действие выполняется в соот- ветствии с точностью общего типа и типом результата явля- ется общий тип. - Выражение справа в операторе присваивания вычисляется не- зависимо от размера или типа переменной слева. - Любые операнды размером в байт преобразуются к промежуточ- ному операнду размером в слово, который совместим перед выполнением арифметической операции с типами Integer и Word. Значение одного целочисленного типа может быть явным образом преобразовано к другому целочисленному типу с помощью приведения типов. Примечание: Приведение типов описывается в Главах 5 и 6.

Булевские типы

Существует 4 предопределенных булевских типа: Boolean, ByteBool, WordBool и LongBool. Значения булевского типа обознача- ются встроенными идентификаторами констант False и True. Посколь- ку булевский тип является перечислимым, между этими значениями имеют место следующие отношения: - False < True - Ord(False) = 0 - Ord(True) = 1 - Succ(False) = True - Pred(True) = False Переменные типа Boolean и ByteBool занимают 1 байт, пере- менная WordBool занимает два байта (слово), а переменная LongBool занимает четыре байта (два слова). Boolean - это наиболее предпо- чтительный тип, использующей меньше памяти; типа ByteBool, WordBool и LongBool обеспечивают совместимость с другими языками и средой Windows. Предполагается, что переменная типа Boolean имеет порядковые значения 0 и 1, но переменные типа ByteBool, WordBool и LongBool могут иметь другие порядковые значения. Когда выражение типа ByteBool, WordBool или LongBool равна 1, то подразумевается, что она имеет значение True, а если оно равно 0 - то False. Когда значение типа ByteBool, WordBool или LongBool используется в кон- тексте, где ожидается значение Boolean, компилятор будет автома- тически генерировать код, преобразующий любое ненулевое значение в значение True.

Символьный тип (char)

Множеством значений этого типа являются символы, упорядочен- ные в соответствии с расширенным набором символов кода ASCII. При вызове функции Ord(Ch), где Ch - значение символьного типа, возв- ращается порядковый номер Ch. Строковая константа с длиной 1 может обозначать значение константы символьного типа. Любое значение символьного типа может быть получено с помощью стандартной функции Chr.

Перечислимые типы

Перечислимые типы определяют упорядоченные множества значе- ний через перечисление идентификаторов, которые обозначают эти значения. Упорядочение множеств выполняется в соответствии с пос- ледовательностью, в которой перечисляются идентификаторы. ---- ---------------- ---- перечислимый -->¦ ( +--->¦ список +--->¦ ) +---> тип L---- ¦идентификаторов¦ L---- L---------------- список -------------- идентификаторов -------->¦идентификатор+---T----> ^ L-------------- ¦ ¦ ---- ¦ L------+ , ¦<------------ L---- При указании идентификатора в списке идентификаторов пере- числимого типа он описывается как константа для блока, в котором указано описание перечислимого типа. Типом этой константы являет- ся описанный перечислимый тип. Порядковый номер перечислимой константы определяется ее по- зицией в списке идентификаторов при описании. Перечислимый тип, в котором описывается константа, становится ее типом. Первая пере- числимая константа в списке имеет порядковый номер 0. Приведем пример перечислимого типа: type suit = (club, diamond, heart, spade); Согласно этим описаниям diamond является константой типа suit. При применении функции Ord к значению перечислимого типа Ord возвращает целое число, которое показывает, какое положение зани- мает это значение в отношении других значений этого перечислимого типа. Согласно предшествующим описаниям, Ord(club) возвращает 0, Ord(diamond) возвращает 1 и так далее.

Отрезки типа

Отрезок типа представляет собой диапазон значений из поряд- кового типа, называемого главным типом. Определение отрезка типа включает наименьшее и наибольшее значение в поддиапазоне. Оно имеет следующий синтаксис: отрезок ------------ ----- ------------ типа ----------->¦ константа +--->¦ .. +--->¦ константа +---> L------------ L----- L------------ Обе константы должны иметь один и тот же порядковый тип. От- резки типов, имеющие вид a..b, предполагают, что a меньше или равно b. Приведем примеры отрезков типов: 0..99 -128..127 club..heart Переменная отрезка типа имеет все свойства переменных глав- ного типа, однако ее значение на этапе выполнения должно принад- лежать указанному интервалу. Разрешение использования выражений-констант там, где стан- дартный Паскаль допускает только простые константы, приводит к некоторой синтаксической неоднозначности. Рассмотрим следующие описания: const X = 50; Y = 10; type Color = (Red, Green, Blue); Scale = (X - Y) * 2..(X + Y) * 2; Согласно синтаксису стандартного Паскаля, если определение типа начинается с круглой скобки, то это перечислимый тип (такой как Color в данном примере). Однако Scale предназначен для опре- деления отрезка типа. Решение состоит в том, чтобы переупорядо- чить первое выражение поддиапазона или задать другую константу, равную значению данного выражения, и использовать эту константу в определении типа: type Scale = 2 * (X - Y)..(X + Y);

Вещественные типы

К вещественному типу относится подмножество вещественных чи- сел, которые могут быть представлены в формате с плавающей точкой с фиксированным числом цифр. Запись значения в формате с плаваю- щей запятой обычно включает три значения - m, b и e - таким обра- зом, что m x b^e=n, где b всегда равен 2, а m и e являются цело- численными значениями в диапазоне вещественного типа. Эти значения m и e далее определяют диапазон представления и точность вещественного типа. Имеется пять видов вещественных типов: вещественное (Real), с одинарной точностью (Single), с двойной точностью (Double), с повышенной точностью (Extended) и сложное (Comp). Действия над типами с одинарной точностью, с двойной точностью и с повышенной точностью и над сложным типом могут выполняться только при нали- чии числового сопроцессора 8087 (который был описан ранее). Вещественные типы различаются диапазоном и точностью связан- ных с ними значений (см. Таблицу 4.2). Диапазон представления и десятичные цифры для вещественных типов Таблица 4.2 ------------------------T---------------------------T----------- ¦ Тип ¦ Диапазон ¦ Цифры ¦ +-----------------------+---------------------------+-----------+ ¦ вещественное ¦2.9x10^-39 .. 1.7x10^38 ¦от 11 до 12¦ ¦ (Real) ¦ ¦ ¦ +-----------------------+---------------------------+-----------+ ¦ с одинарной точностью ¦1.5x10^-45 .. 3.4x10^38 ¦от 7 до 8 ¦ ¦ (Single) ¦ ¦ ¦ +-----------------------+---------------------------+-----------+ ¦ с двойной точностью ¦5.0x10^-324 .. 1.7x10^308 ¦от 15 до 16¦ ¦ (Double) ¦ ¦ ¦ +-----------------------+---------------------------+-----------+ ¦ с повышенной точностью¦1.9x10^-4951 .. 1.1x10^4932¦от 19 до 20¦ ¦ (Extended) ¦ ¦ ¦ +-----------------------+---------------------------+-----------+ ¦ сложный тип ¦ -2^63 + 1 .. 2^63 - 1 ¦ ¦ ¦ (Comp) ¦ ¦ ¦ L-----------------------+---------------------------+------------ Примечание: Сложный тип содержит только целочисленные значения в диапазоне от -2^63+1 до 2^63-1, что приблизи- тельно равно -9.2x10^18 и 9.2x10^18. Borland Pascal поддерживает две модели генерации кода для выполнения действий над вещественными типами: программную для чи- сел с плавающей точкой и аппаратную для чисел с плавающей точкой. Выбор соответствующей модели осуществляется с помощью директивы компилятора $N.

Программная поддержка чисел с плавающей точкой

В состоянии {$N-}, которое устанавливается по умолчанию, ге- нерируемый код выполняет все вычисления с вещественными типами программно, через вызов подпрограмм библиотеки исполняющей систе- мы. Из-за соображений скорости и размера кода в этом состоянии допускаются только действия над переменными типа real (веществен- ное). Любая попытка оттранслировать операторы, выполняющие дейс- твия над типами с одинарной точностью, с двойной точностью, с по- вышенной точностью и над сложными типами, вызовет сообщение об ошибке.

Аппаратная поддержка чисел с плавающей точкой

В состоянии {$N+} генерируемый код выполняет все вычисления над вещественными типами с помощью числового сопроцессора 8087. Это состояние позволяет использовать все пять вещественных типов, однако оно требует наличия сопроцессора 8087 на этапе компиляции и выполнения. Borland Pascal включает в себя библиотеки исполняющей систе- мы, которые автоматически эмулируют программным путем сопроцессор 80х87, если при выполнении прикладной программы DOS реального или защищенного режима он отсутствует. Для определения того, следует ли в программу DOS включить эмулятор сопроцессора 80x87, исполь- зуется директива компилятора $E. Если вы создает прикладную прог- рамму для реального или защищенного режима DOS, и сопроцессор 80х87 отсутствует, разрешение директивы компилятора $E обеспечи- вает полную программную эмуляцию сопроцессора 80x87. Для программ Windows директива $E не действует, так как Windows обеспечивает собственные подпрограммы эмуляции. Примечание: Более детальное описание генерации кода при аппаратной поддержке чисел с плавающей запятой вы може- те найти в Главе 15 "Использование сопроцессора 8087 в Borland Pascal".

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

Значением строкового типа является последовательность симво- лов с динамическим атрибутом длины (в зависимости от действитель- ного числа символов при выполнении программы) и постоянным атри- бутом размера в диапазоне от 1 до 255. Текущее значение атрибута длины можно получить с помощью стандартной функции Length. ------- строковый тип --->¦string+--T------------------------------> L------- ¦ ^ ¦ ---- ------ ---- ¦ L->¦ [ +-->¦целое+-->¦ ] +-- L---- ¦ без ¦ L---- ¦знака¦ L------ Примечание: Операторы работы со строковыми типами опи- сываются разделах "Строковые операторы" и "Операторы отно- шений" Главы 6. Отношение между любыми двумя строковыми значениями устанав- ливается согласно отношению порядка между значениями символов в соответствующих позициях. В двух строках разной длины каждый сим- вол более длинной строки без соответствующего символа в более ко- роткой строке принимает значение "больше"; например, 'Xs' больше, чем 'X'. Нулевые строки могут быть равны только другим нулевым строкам, и они являются наименьшими строковыми значениями. Примечание: Стандартные процедуры и функции для работы со строковыми типами описаны в разделе "Строковые процедуры и функции". К символам в строках можно обращаться как к элементам масси- ва. См. раздел "Массивы, строки и индексы" в Главе 5. К идентификатору строкового типа и к ссылке на переменную строкового типа можно применять стандартные функции Low и High. В этом случае функция Low возвращает 0, а High возвращает атрибут размера (максимальную длину) данной строки. Параметр-переменная, описанная с помощью идентификатора OpenString и ключевого слова string в состоянии {$P+}, является открытым строковым параметром. Открытые строковые параметры поз- воляют передавать одной и той же процедуре или функции строковые переменные изменяющегося размера. Примечание: Открытые строковые параметры описываются в Главе 9.

Структурные типы

Структурный тип, характеризуемый методом структурирования и типами своих компонентов, имеет более одного значения. Если тип компонента является структурным, то получаемый в результате структурный тип имеет более одного уровня структурирования. Структурный тип может иметь неограниченные уровни структурирова- ния. ---------------- структурный --T----------------T-->¦ тип массив +-----> тип ¦ --------- ^ ¦ L---------------- ^ L->¦ packed +-- ¦ ---------------- ¦ L--------- +-->¦ множественный +--+ ¦ ¦ тип ¦ ¦ ¦ L---------------- ¦ ¦ ---------------- ¦ +-->¦ файловый тип +--+ ¦ L---------------- ¦ ¦ ---------------- ¦ +-->¦ тип "запись" +--+ ¦ L---------------- ¦ ¦ ---------------- ¦ L-->¦ объектный тип +--- L---------------- Слово packed (упакованный) в описании структурного типа тре- бует от компилятора уплотнить хранимые данные, даже за счет уменьшения скорости доступа к компоненту в переменной этого типа. Слово packed не имеет никакого действия в Borland Pascal, пос- кольку упаковка выполняется здесь автоматически всюду, где это возможно.

Типы массив

Массивы содержат фиксированное число элементов одного типа, так называемого типа элемента. На приводимой ниже синтаксической диаграмме тип элемента следует за словом of. -------- ---- -------- ---- ----- ------ тип -->¦ array +->¦ [ +--->¦ тип +-T->¦ ] +->¦ of +->¦ тип +> массив L-------- L---- ^ ¦индекса¦ ¦ L---- L----- L------ ¦ L-------- ¦ ¦ ---- ¦ L----+ , ¦<--- L---- тип ----------------- индекса --->¦ порядковый тип +---> L----------------- В индексных типах, по одному для каждой размерности массива, указывается число элементов. Допустимыми индексными типами явля- ются все порядковые типы, за исключением длинного целого и подди- апазонов длинного целого. Массив может быть проиндексирован по каждой размерности всеми значениями соответствующего индексного типа; число элементов поэтому равно числу значений в каждом ин- дексном типе. Число размерностей не ограничено. Приведем пример типа массив: array[1..100] of Real Если тип элемента в типе массив также является массивом, то результат можно рассматривать как массив массивов или как один многомерный массив. Например, array[boolean] of array[1..100] of array[Size] of Real интерпретируется компилятором точно так же, как массив: array[boolean,1..10,Size] of Real Кроме того, можно записать выражение: packed array[1..10] of packed array[1..8] of Boolean как packed array[1..10,1..8] of Boolean Для доступа к элементам массива необходимо указать идентифи- катор массива с одним или несколькими индексами в скобках (см. раздел "Массивы, строки и индексы"). Тип массив, имеющий вид: packed array[M..N] of Char где M меньше N, называется упакованным строковым типом (слово packed можно опустить, поскольку оно не оказывает действия в Borland Pascal). Упакованный строковый тип имеет некоторые свойс- тва, не характерные для других типов массив (см. раздел "Тождест- венные и совместимые типы" далее в этой главе). Массив вида: array[0..X] of Char где X - положительное целое число, называется массивом с нулевой базой. Массивы с нулевой базой используются для хранения строк с завершающим нулем, и, когда разрешен расширенный синтаксис (с по- мощью директивы компилятора {$X+}), символьный массив с нулевой базой совместим со значением типа PChar. Полностью эта тема об- суждается в Главе 18 "Использование строк с завершающим нулем". Параметр, описанный с помощью синтаксиса array of T, называ- ется открытым строковым параметром. Открытые строковые параметры позволяют передавать одной и той же процедуре или функции строко- вые переменные изменяющегося размера. Примечание: Открытые строковые параметры описываются в Главе 9.

Типы запись

Тип запись содержит установленное число элементов или полей, которые могут быть различных типов. Описание типа запись указыва- ет тип каждого поля и идентификатор, который именует поле. --------- ------ тип запись --->¦ record +--T---------------->¦ end +--> L--------- ¦ --------- ^ L------ L->¦ список +-- ¦ полей ¦ L--------- список ------------- полейT->¦ фиксирован-+-T----------------------------T----------> ¦ ¦ ная часть ¦ ¦ ---- ------------- ^ ¦ ---- ^ ¦ L------------- L->¦ ; +--->¦ вариантная +-- L->¦ ; +-- ¦ L---- ^ ¦ часть ¦ L---- L--------------------------- L------------- ------------------ ---- ------ фиксированная ---->¦ список +-->¦ : +--->¦ тип +--T--> часть ^ ¦ идентификаторов ¦ L---- L------ ¦ ¦ L------------------ ¦ ¦ ¦ ¦ ---- ¦ L------------+ ; ¦<------------------------- L---- Фиксированная часть типа запись содержит список фиксирован- ных полей вместе с идентификатором и типом для каждого поля. Каж- дое поле содержит информацию, которая всегда отыскивается одним и тем же способом. Приведем пример типа запись: record year: integer; { год } month: 1..12; { месяц } day: 1..31; { число } end В вариантной части, изображенной на синтаксической диаграмме описания типа запись, память распределяется более чем для одного списка полей, поэтому доступ к информации может быть осуществлен более чем одним способом. Каждый список полей является вариантом. Варианты налагаются друг на друга в памяти, поэтому в любое время возможен доступ ко всем полям во всех вариантах. вариантная часть ¦ ----- --------- --- -------- L->¦case+-T------------------->¦тип поля+->¦of+---->¦вариант+-T> L----- ¦ ^ ¦признака¦ L--- ^ L-------- ¦ ¦ -------- ---- ¦ L--------- ¦ ---- ¦ L>¦иденти-+>¦ : +-- L----+ ; ¦<---- ¦фикатор¦ L---- L---- L-------- ----------------- тип поля ---->¦ идентификатор +----> признака ¦порядкового типа¦ L----------------- ---------- ---- ---- ---- вариант ---->¦константа+-T->¦ : +->¦ ( +-T------------->¦ ) +--> ^ L---------- ¦ L---- L---- ¦ ^ L---- ¦ ---- ¦ ¦ ¦ L----+ , ¦<----- ¦ ------- ¦ L---- L->¦список+-- ¦полей ¦ L------- Вы можете видеть на диаграмме, что каждый вариант идентифи- цирован по крайней мере одной константой. Все константы должны быть отличными друг от друга и иметь порядковый тип, совместимый с типом поля признака. Доступ к вариантным и фиксированным полям один и тот же. В вариантной части можно указать необязательный идентифика- тор - идентификатор признака поля. При наличии идентификатора признака поля он становится идентификатором дополнительного фик- сированного поля записи - поля признака. Программа может исполь- зовать значение поля признака для указания, какой вариант являет- ся активным в настоящий момент. Без указания поля признака программа выбирает вариант по другому критерию. Ниже приводятся несколько примеров типов запись: record firstName,lastName : string[40]; birthDate : Date; case citizen : boolean of True : (birthPlace: string[40]); False : (country : string[20]; entryPort : string[20]; entryDate : Date; exitDate : Date); end record x,y : real; case kind : Figure of rectangle : (height,wigth: real); { прямоугольник } triangle : (size1,side2,angle: real); { треугольник } circle : (radius: real); { круг } end

Объектные типы

Объектный тип является структурой, состоящей из фиксирован- ного числа компонентов. Каждый компонент является либо полем, со- держащим данные строго определенного типа, либо методом, выполня- ющим операции над объектом. По аналогии с описанием переменных, описание поля указывает тип данного этого поля и идентификатор, именующий поле: по аналогии с описанием процедуры или функции, описание метода указывает заголовок процедуры, функции, конструк- тора или деструктора. Объектный тип может наследовать компоненты другого объектно- го типа. Если T2 наследует от T1, то T2 является потомком T1, а T1 является родителем T2. Наследование является транзитивным, то есть если T3 наследу- ет от T2, а T2 наследует от T1, то T3 наследует от T1. Область (домен) объектного типа состоит из него самого и из всех его нас- ледников. ------- ----------------- тип объекта-->¦object+-T------------------->¦список компонент+- L------- ¦ ------------- ^ L----------------- ¦ L->¦Hаследование+-- ¦ L------------- ¦ --------------------------------------------- ¦ ---- L-T----------------------------------T-+end+> ¦ -------- ----------------- ¦ L---- L-->¦private+-->¦список компонент+-- L-------- L----------------- ---- ------------------------------ ---- наследование -->¦ ( +->¦идентификатор объектного типа+->¦ ) +--> L---- L------------------------------ L---- список компонент --T-----------------T-------------------> ¦ --------- ^ ¦ ---------- ^ L->¦ список +--- L->¦ список +--- ¦ полей ¦ ¦ методов ¦ L--------- L---------- ----------------------- ---- ----- ---- список полей --->¦cписок идентификаторов+->¦ : +->¦type+>¦ ; +T> ^ L----------------------- L---- L----- L----¦ ¦ ¦ L------------------------------------------------ ---------- ---- список методов -->¦заголовок+-T--------------------------+ ; +T-> ^ ¦ метода ¦ ¦ ---- -------- ^L----¦ ¦ L---------- L>¦ ; +->¦virtual+T-------- ¦ ¦ L---- L--------¦ ^ ¦ ¦ ¦ L--------¦ ¦ ¦ ----------¦¦ ¦ L>¦ целая +-¦ ¦ ¦константа¦ ¦ ¦ L---------- ¦ L----------------------------------------------- ------------------------- заголовок метода ----T--->¦ заголовок процедуры +------> ¦ L------------------------- ^ ¦ ------------------------- ¦ +--->¦ заголовок функции +--+ ¦ L------------------------- ¦ ¦ ------------------------- ¦ +--->¦ заголовок конструктора +--+ ¦ L------------------------- ¦ ¦ ------------------------- ¦ L--->¦ заголовок деструктора +--- L------------------------- Следующий исходный код приводит пример описания объектного типа. Далее во всей этой главе на данное описание будут делаться ссылки. type Point = object X, Y: integer; end; Rect = object A, B: TPoint; procedure Init(XA, YA, XB, YB: Integer); procedure Copy(var R: TRectangle); procedure Move(DX, DY: Integer); procedure Grow(DX, DY: Integer); procedure Intersect(var R: TRectangle); procedure Union(var R: TRectangle); function Contains(P: Point): Boolean; end; StringPtr = ^String; FieldPtr = ^TField; TField = object X, Y, Len: Integer; Name: StringPtr; constructor Copy(var F: TField); constructor Init(FX, FY, FLen: Integer; FName: String); destructor Done; virtual; procedure Display; virtual; procedure Edit; virtual; function GetStr: String; virtual; function PutStr(S: String): Boolean; virtual; end; StrFieldPtr = ^TStrField; StrField = object(TField) Value: PString; constructor Init(FX, FY, FLen: Integer; FName: String); destructor Done; virtual; function GetStr: String; virtual; function PutStr(S: String): Boolean; virtual; function Get: string; procedure Put(S: String); end; NumFieldPtr = ^TNumField; TNumField = object(TField) private Value, Min, Max: Longint; public constructor Init(FX, FY, FLen: Integer; FName: String; FMin, FMax: Longint); function GetStr: String; virtual; function PutStr(S: String): Boolean; virtual; function Get: Longint; function Put(N: Longint); end; ZipFieldPtr = ^TZipField; ZipField = object(TNumField) function GetStr: String; virtual; function PutStr(S: String): Boolean; virtual; end; В отличие от других типов, объектные типы могут описываться только в разделе описаний типов, находящемся на самом внешнем уровне области действия программы или модуля. Таким образом, объ- ектные типы не могут описываться в разделе описаний переменных или внутри блока процедуры, функции или метода. Тип компоненты файлового типа не может иметь объектный тип или любой структурный тип, содержащий компоненты объектного типа.

Компоненты и область действия

Область действия идентификатора компоненты простирается за пределы объектного типа. Более того, область действия идентифика- тора компонента простирается сквозь блоки процедур, функций, конструкторов и деструкторов, которые реализуют методы объектного типа и его наследников. Исходя из этих соображений, написание идентификатора компоненты должно быть уникальным внутри объектно- го типа и внутри всех его наследников, а также внутри всех его методов. Область действия идентификатора компонента, описанного в части private описания типа, ограничивается модулем (программой), которая содержит описание объектного типа. Другими словами, част- ные (private) компоненты-идентификаторы действуют, как обычные общедоступные идентификаторы в рамках модуля, который содержит описание объектного типа, а вне модуля любые частные компоненты и идентификаторы неизвестны и недоступны. Поместив в один модуль связанные типы объектов, можно сделать так, что эти объекты смо- гут обращаться к частным компонентам друг друга, и эти частные компоненты будут неизвестны другим модулям. В описании объектного типа заголовок метода может задавать параметры описываемого объектного типа, даже если описание еще не полное. Это иллюстрируется методами Copy, Intersect и Union типа TRectange в предыдущем примере.

Методы

Описание метода внутри объектного типа соответствует опере- жающему описанию метода (forward). Таким образом, где-нибудь пос- ле описания объектного типа, но внутри той же самой области дейс- твия, что и область действия описания объектного типа, метод дол- жен реализоваться путем определения его описания. Если требуется уникальный идентификатор метода, то использу- ется уточненный идентификатор метода. Он состоит из идентификато- ра типа объекта, за которым следуют точка и идентификатор метода. Как и любому другому идентификатору, идентификатору уточненного метода, если требуется, могут предшествовать идентификатор пакета и точка. уточненный идентификатор метода ¦ ------------------------------ ---- --------------------- L->¦идентификатор объектного типа+>¦ . +>¦идентификатор метода+> L------------------------------ L---- L---------------------

Виртуальные методы

По умолчанию, методы являются статическими, однако они мо- гут, за исключением конструкторов, быть виртуальными (посредством включения директивы virtual в описание метода). Компилятор разре- шает ссылки на вызовы статических методов во время процесса ком- пиляции, тогда как вызовы виртуальных методов разрешаются во вре- мя выполнения. Это иногда называют поздним связыванием. Если объектный тип объявляет или наследует какой-либо вирту- альный метод, то переменные этого типа должны быть инициализиро- ваны посредством вызова конструктора перед вызовом любого вирту- ального метода. Таким образом, объектный тип, который описывает или наследует виртуальный метод, должен также описывать или нас- ледовать по крайней мере один метод-конструктор. Объектный тип может переопределять любой из методов, которые он наследует от своих родителей. Если описание метода в потомке указывает тот же идентификатор метода, что и описание метода в родителе, то описание в потомке переопределяет описание в родите- ле. Область действия переопределяющего метода расширяется до сфе- ры действия потомка, в котором этот метод был введен, и будет ос- таваться таковой, пока идентификатор метода не будет переопреде- лен снова. Переопределение статического метода не зависит от изменения заголовка метода. В противоположность этому, переопределение вир- туального метода должно сохранять порядок, типы и имена парамет- ров, а также типы результатов функций, если таковые имеются. Бо- лее того, переопределение опять же должно включать директиву virtual.

Динамические методы

Borland Pascal поддерживает дополнительные методы с поздним связыванием, которые называются динамическими методами. Динами- ческие методы отличаются от виртуальных только характером их дис- петчеризации на этапе выполнения. Во всех других отношениях дина- мические методы считаются эквивалентными виртуальным. Описание динамического метода эквивалентно описанию вирту- ального метода, но описание динамического метода должно включать в себя индекс динамического метода, который указывается непос- редственно за ключевым словом virtual. Индекс динамического мето- да должен быть целочисленной константой в диапазоне от 1 до 656535 и должен быть уникальным среди индексов других динамичес- ких методов, содержащихся в объектном типе или его предках. Нап- ример: procedure FileOpen(var Msg: TMessage); virtual 100; Переопределение динамического метода должно соответствовать порядку, типа и именам параметров и точно соответствовать типу результата функции порождающего метода. Переопределение также должно включать в себя директиву virtual, за которой следует тот же индекс динамического метода, который был задан в объектном ти- пе предка. Примечание: Подробнее о динамических методах и о раз- нице в диспетчеризации динамических и виртуальных методов рассказывается в Главе 22.

Создание экземпляров объектов

Экземпляр объекта создается посредством описание переменной или константы объектного типа или путем применения стандартной процедуры New к переменной типа указатель на объектный тип. Ре- зультирующий объект называется экземпляром объектного типа. var F: TField; Z: TZipField; FP: PField; ZP: PZipField; С учетом этих описание переменных F является экземпляром TField, а Z - экземпляром TZipField. Аналогично, после применения New к FP и ZP, FP будет указывать на экземпляр TField, а ZP - на экземпляр TZipField. Если объектный тип содержит виртуальные методы, то экземпля- ры этого объектного типа должны инициализироваться посредством вызова конструктора перед вызовом любого виртуального метода. Ни- же приведен пример: var S: StrField; begin S.Init (1, 1, 25, 'Первое имя'); S.Put ('Френк'); S.Display; ... S.Done; end; Если S.Init не вызывался, то вызов S.Display приведет к неу- дачному завершению данного примера. Присваивание экземпляра объектного типа не подразумевает инициализации экземпляра. Объект инициализируется кодом, генерируемым компилятором, который выполняется между вызовом конструктора, и когда выполне- ние фактически достигает первого оператора в блоке кода конструк- тора. Если экземпляр объекта не инициализируется, и проверка диа- пазона включена (директивой {$R+}), то первый вызов виртуального метода экземпляра объекта дает ошибку этапа выполнения. Если про- верка диапазона выключена (директивой {$R-}), то первый виртуаль- ного метода неинициализированного объекта может привести к неп- редсказуемому поведению. Правило обязательной инициализации применимо также к экземп- лярам, которые являются компонентами структурных типов. Например: var Comment: array [1..5] of TStrField; I: integer; begin for I := 1 to 5 do Comment [I].Init (1, I + 10, 40, 'первое_имя'); . . . for I := 1 to 5 do Comment [I].Done; end; Для динамических экземпляров инициализация, как правило, связана с размещением, а очистка - с удалением, что достигается благодаря расширенному синтаксису стандартных процедур New и Dispose. Например: var SP: StrFieldPtr; begin New (SP, Init (1, 1, 25, 'первое_имя'); SP^.Put ('Френк'); SP^.Display; . . . Dispose (SP, Done); end; Указатель на объектный тип является совместимым по присваи- ванию с указателем на любой родительский объектный тип, поэтому во время выполнения программы указатель на объектный тип может указывать на экземпляр этого типа или на экземпляр любого дочер- него типа. Например, указатель типа ZipFieldPtr может присваиваться указателям типа PZipField, PNumField и PField, а во время выпол- нения программы указатель типа PField может либо иметь значение nil, либо указывать на экземпляр TField, TNumField или TZipField, или на любой экземпляр дочернего по отношению к TField типа. Эти правила совместимости указателей по присваиванию приме- нимы также к параметрам-переменным объектного типа. Например, ме- тоду TField.Copy могут быть переданы экземпляры типов TField, TStrField, TNumField, TZipField или любые другие экземпляры до- чернего от TField типа.

Активизация методов

Метод активизируется посредством оператора вызова процедуры или функции, состоящего из десигнатора метода, за которым следует список параметров. Такой тип вызова называется активизацией мето- да. десигнатор метода ¦ --------------------- L-T-------------------------------------->¦идентификатор метода+> ¦ ^ L--------------------- ¦ ----------------------- ---- ¦ L>¦ ссылка на переменную +>¦ . +----- L----------------------- L---- Ссылка на переменную задается, если десигнатор метода должен описывать экземпляр объектного типа, а идентификатор метода дол- жен обозначать метод этого объектного типа. Экземпляр, обозначенный десигнатором метода, становится не- явным фактическим параметром метода; он соответствует формальному параметру-переменной с именем Self, который владеет объектным ти- пом, соответствующим активизированному методу. Для статических методов описанный тип (на этапе компиляции) определяет, какой из методов активизируется. Например, десигнато- ры F.Init и FP^.Init всегда активизируют TField.Init, так как описанным типом F и FP^ является TField. Для виртуальных методов выбором экземпляра управляет факти- ческий тип (этапа выполнения). Например, десигнатор FP^.Display может активизировать методы TField.Display, TStrField.Display, TNumField.Display или TZipField.Display (в зависимости от факти- ческого типа экземпляра, указываемого FP). В операторе with, ссылающемся на экземпляр объектного типа, ссылка на переменную в десигнаторе метода может опускаться. В этом случае экземпляром, на который ссылается оператор with, ста- новится неявный параметр Self активизации метода. Аналогично, ссылка не переменную может опускаться в методе. В этом случае параметром Self метода, содержащего вызов, становится неявный па- раметр Self активизации метода.

Активизация уточненных методов

В методе, операторе вызова функции или процедуры для обозна- чения активизации конкретного метода допускается использование десигнатора уточненного метода. Такой тип вызова называется акти- визацией уточненного метода. десигнатор уточненного метода ¦ ----------------------- ---- --------------------- L-T>¦ идентификатор +>¦ . +------->¦идентификатор метода+> ¦ ¦ объектного типа ¦ L---- ^ L--------------------- ¦ L----------------------- ¦ ¦ ----------------------- ¦ L>¦ inherited +----------- L----------------------- Объектный тип, заданный в десигнаторе уточненного метода, должен быть таким же, как и включающий метод объектный тип, или соответствовать родительскому типу. Для обозначения родительского объектного типа или объектного типа, включающего метод, можно использовать ключевое слово inherited; в методах объектного типа, не имеющего предка, ключе- вое слово inherited использоваться не может. Неявный параметр Self активизации уточненного метода стано- вится параметром Self метода, содержащего вызов. Активизация уточненных методов не предусматривает механизма диспетчеризации виртуальных методов - вызов будет всегда статическим и всегда вы- зывает заданный метод. Активизация уточненного метода используется обычно в переоп- ределяющем методе для активизации переопределяющего метода. С учетом описанных выше типов приведем некоторые примеры активиза- ции уточненных методов: constructor TNumField.Init(Fx, FY, Flen: Integer; FName: String; FMin, FMax: Longint); begin inherited Init(FX, FY, FLen, FName); Value := 0; Min := FMin; Max := FMax; end; function TZipField.PutStr(S: String): Boolean; begin PutStr := (Length(S) = 5) and TNumField.PutStr(S); end; Как показывают эти примеры, активизация уточненных методов позволяет переопределяющему методу "вновь использовать" код мето- да, который он переопределяет.

Множественные типы

Диапазон значений множественного типа представляет собой мощность множества для определенного порядкового типа (базового типа). Каждое возможное значение множественного типа является подмножеством возможных значений базового типа. Переменная множественного типа может принимать как все зна- чения множества, так и ни одного. ------ ----- ----------------- тип множество --->¦ set +--->¦ of +--->¦ порядковый тип +---> L------ L----- L----------------- Базовый тип не должен иметь более 256 возможных значений, и порядковые значения верхней и нижней границы базового типа должны не превышать диапазона от 0 до 255. В силу этого базовый тип мно- жества не может быть коротким целым (Shortint), целым (Integer), длинным целым (Longint) или словом (Word). Примечание: Операции над множественными типами описыва- ются в разделе "Операции над множествами" в Главе 6. В раз- деле "Описатели множеств" показано, как определять значения множества. Любой множественный тип может принимать значение [], которое называется пустым множеством.

Файловые типы

Файловый тип состоит из линейной последовательности компо- нентов, которые могут иметь любой тип за исключением файлового типа или структурного типа, содержащего компонент с файловым ти- пом. Число компонентов описанием файлового типа не устанавливает- ся. ------- ----- ------ файловый тип --->¦ file +--T->¦ of +--->¦ тип +-----> L------- ¦ L----- L------ ^ L---------------------- Если слово of и тип компонента опущены, то тип обозначает нетипизированный файл. Нетипизированные файлы представляют собой каналы ввода-вывода нижнего уровня, в основном используемые для прямого доступа к любому файлу на диске, независимо от его внут- реннего формата. Стандартный файловый тип Text определяет файл, содержащий символы, упорядоченные в строки. Текстовые файлы используют спе- циальные процедуры ввода-вывода, которые описываются в Главе 14 "Ввод и вывод".

Ссылочные типы

Cсылочный тип (указатель) определяет множество значений, ко- торые указывают на динамические переменные определенного типа, называемого базовым типом. Переменная ссылочного типа содержит адрес динамической переменной в памяти. ---- -------------- ссылочный тип ------>¦ ^ +--->¦ базовый тип +--> L---- L-------------- ---------------------- базовый тип ---->¦ идентификатор типа +---> L---------------------- Если базовый тип является еще не описанным идентификатором, то он должен быть описан в той же самой части описания типов, что и тип указатель. Переменной-указателю можно присвоить значение с помощью про- цедуры New, операции @ или функции Ptr. Процедура New отводит но- вую область памяти в динамически распределяемой области для дина- мических переменных и сохраняет адрес этой области в переменной указателя. Операция @ ориентирует переменную-указатель на область памяти, содержащую существующую переменную, включая и те перемен- ные, которые имеют идентификаторы. Функция Ptr ориентирует пере- менную-указатель на определенный адрес в памяти. Зарезервированное слово nil обозначает константу со значени- ем указателя, которая ни на что не указывает.

Тип Pointer

Встроенный тип Pointer обозначает нетипизированный указа- тель, то есть указатель, который не указывает ни на какой опреде- ленный тип. Переменные типа Pointer могут быть разыменованы: ука- зание символа ^ после такой переменной вызывает появление ошибки. Как и значение, обозначаемое словом nil, значения типа Pointer совместимы со всеми другими типами указателей. Примечание: В разделе "Указатели и динамические пере- менные" в Главе 5 вы можете найти синтаксис ссылки на дина- мические переменные, которые указываются с помощью указате- ля-переменной.

Тип PChar

Для представления указателя на строку с завершающим нулем в Borland Pascal имеется предопределенный тип PChar. В блоке System данный тип описывается следующим образом: type PChar = ^Char; Borland Pascal поддерживает набор расширенных правил, позво- ляющих работать со строками с завершающим нулем, используя тип PChar. Полностью эта тема обсуждается в Главе 18 "Использование строк с завершающим нулем".

Процедурные типы

В стандартном Паскале процедуры и функции рассматриваются только как части программы, которые можно выполнять с помощью вы- зова процедуры или функции. В Borland Pascal процедуры и функции трактуются гораздо шире: здесь допускается интерпретация процедур и функций, как объектов, которые можно присваивать переменным и передавать в качестве параметров. Такие действия можно выполнять с помощью процедурных типов. В описании процедурного типа задаются параметры, а для функ- ции - результат функции. процедурный тип ¦ ¦ ---------- LT>¦procedure+-T-----------------------------------------------> ¦ L---------- ¦ ----------------------------- ^ ^ ¦ L->¦список формальных параметров+-- ¦ -- L----------------------------- L- ¦ --------- ---- ----------¦ L>¦function+T-------------------------------->¦ : +>¦результат+- L---------¦ -----------------------------^ L---- L---------- L>¦список формальных параметров+- L----------------------------- Характерно, что синтаксис записи процедурного типа в точнос- ти совпадает с записью заголовка процедуры или функции, только опускается идентификатор после ключевого слова procedure или function. Приведем некоторые примеры описаний процедурного типа: type Proc = procedure; SwapProc = procedure(var X, Y: Integer); StrProc = procedure(S: String); MathFunc = function(X: Real): Real; DeviceFunc = function(var F: text): Integer; MaxFunc = function(A, B: Real; F: MathFunc): Real; Имена параметров в описании процедурного типа играют чисто декоративную роль - на смысл описание они не влияют. Borland Pascal не позволяет описывать функции, которые возв- ращают значения процедурного типа. Результат функции должен быть строкового, вещественного, целого, символьного, булевского типа, указателем или иметь перечислимый тип, определенный пользовате- лем.

Процедурные значения

Переменной процедурного типа можно присвоить процедурное значение. Процедурные значения могут быть следующими: * значениями nil; * ссылкой на переменную процедурного типа; * идентификатором процедуры или функции. В контексте процедурных значений описание процедуры или функции можно рассматривать как специальный вид описаний конс- тант, когда значением константы является процедура или функция. Рассмотрим, например, следующее описание: var P: SwapProc; F: MathFunc; procedure Swap(var A, B: Integer); far; var Temp: Integer; begin Temp := A; A := B; B := Temp; end; function Tan(Angle: Real); far; begin Tan := Sin(Angle) / Cos(Angle); end; Переменным P и F можно присвоить значения следующим образом: P := Swap; F := Tan; а вызовы с помощью P и F можно выполнить так: P(I, J); { эквивалентно Swap(I, J) } X := F(X); { эквивалентно X := Tan(X) } Использование процедурных переменных, которым в операторе вызова процедуры или функции присваивается значение nil, приводит к ошибке. Значение nil предназначено для указания того, что про- цедурная переменная не присвоена, и, так где процедурная перемен- ная может получить значение nil, участвующие в этой процедурной переменной вызовы процедур и функций следует подвергать проверке: if @P <> nil then P(I, J); Обратите внимание на использование операции @ для указания того, что P проверяется, а не вызывается.

Совместимость типов

Чтобы они считались совместимыми, процедурные типы должны иметь одно и то же число параметров, а параметры в соответствую- щих позициях должны иметь тождественные типы. При определении совместимости процедурных типов имена параметров значения не име- ют. Значение nil совместимо с любым процедурным типом. Чтобы использоваться в качестве процедурных значений, проце- дуры и функции должны описываться с директивой far и компилиро- ваться в состоянии с {$F+}. Кроме того, в качестве процедурных значений не могут указываться стандартные процедуры и функции, вложенные процедуры и функции, методы, процедуры и функции, опи- санные с ключевым словом inline или interrupt. Стандартные процедуры и функции - это подпрограммы, описан- ные в модуле Unit, например, WriteLn, ReadLn, Chr или Ord. Чтобы использовать в качестве процедурного значения стандартную проце- дуру и функцию, напишите для нее "оболочку". Например, следующая функция DSin совместима по присваиванию с описанным выше типом MathFunc: function FSin(X: Real): Real; far; begin FSin := Sin(X); end; Процедура или функция является вложенной, когда она описыва- ется внутри другой процедуры или функции. Такие вложенные проце- дуры и функции не могут использоваться в качестве процедурных значений.

Тождественные и совместимые типы

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

Тождественность типов

Тождественность типов требуется только для переменных факти- ческих и формальных параметров при вызове процедур и функций. Два типа, скажем T1 и T2, являются тождественными, если яв- ляется истинным одно из следующих утверждений: T1 и T2 представ- ляю собой один и тот же идентификатор типа; T1 описан как эквива- лентный типу, тождественному T2. Второе условие означает, что T1 не обязательно должен быть описан как непосредственно эквивалентный T2. Следующие описания типов: T1 = integer; T2 = T1; T3 = integer; T4 = T2; означают, что T1, T2, T3, T4 и integer являются тождественными типами. Следующие описания типов: T5 = set of integer; T6 = set of integer; не определяют T5 и T6 как тождественные, поскольку set of integer не является идентификатором типа. Две переменные, описанные в од- ном и том же описании, например: V1, V2: set of integer; имеют тождественные типы, поскольку их описания не раздельны. Описания: V1: set of integer; V2: set of integer; V3: integer; V4: integer; означают, что V3 и V4 имеют тождественный тип, а V1 и V2 - нет.

Совместимость типов

Иногда, например, в выражениях и операциях сравнения, требу- ется совместимость типов. Совместимость типов, кроме того, явля- ется важной предпосылкой для совместимости по присваиванию. Совместимость типов имеет место, если выполняется по крайней мере одно из следующих условий: * Оба типа являются одинаковыми. * Оба типа являются вещественными типами. * Оба типа являются целочисленными. * Один тип является поддиапазоном другого. * Оба типа являются отрезками одного и того же основного ти- па. * Оба типа являются множественными типами с совместимыми ба- зовыми типами. * Один тип является строковым типом, а другой - строковым типом, упакованным строковым типом или типом PChar; * Один тип - это тип Pointer, а другой - любой ссылочный тип. * Один тип является типом PChar, а другой - символьным мас- сивом с нулевой базой вида array[0..X] of Char (это дейс- твует только при разрешении директивой {$X+} расширенного синтаксиса). * Оба типа являются указателями идентичных типов (это дейс- твует только при разрешении указателя с проверкой типа ди- рективой {$X+}). * Оба типа являются процедурными с идентичными типами ре- зультатов, одинаковым числом параметров и соответствием между параметрами.

Совместимость по присваиванию

Совместимость по присваиванию необходима, если имеет место присваивание значения, например, в операторе присваивания или при передаче значений параметров. Значение типа T1 является совместимым по присваиванию с ти- пом T2 (то есть допустим оператор T1:=T2), если выполняется одно из следующих условий: * T1 и T2 имеют тождественные типы, и ни один из них не яв- ляется файловым типом или структурным типом, содержащим компонент с файловым типом на одном из своих уровней. * T1 и T2 являются совместимыми порядковыми типами, и значе- ния типа T2 попадают в диапазон возможных значений T1. * T1 и T2 являются вещественными типами, и значения типа T2 попадают в диапазон возможных значений T1. * T1 является вещественным типом, а T2 является целочислен- ным типом. * T1 и T2 являются строковыми типами. * T1 является строковым типом, а T2 является символьным ти- пом (Char). * T1 является строковым типом, а T2 является упакованным строковым типом. * T1 и T2 являются совместимыми упакованными строковыми ти- пами. * T1 и T2 являются совместимыми множественными типами, и все члены значения типа T2 попадают в диапазон возможных зна- чений T1. * T1 и T2 являются совместимыми типами указателей. * T1 - это тип PChar, а T2 - это строковая константа (это действует только при разрешении директивой {$X+} расширен- ного синтаксиса). * T1 является типом PChar, а T2 - символьным массивом с ну- левой базой вида array[0..X] of Char (это действует только при разрешении директивой {$X+} расширенного синтаксиса). * T1 и T2 являются совместимыми процедурными типами. * T1 представляет собой процедурный тип, а T2 - процедура или функция с идентичным типом результата, идентичным чис- лом параметров и соответствием между типами параметров. * Объектный тип T2 совместим по присваиванию с объектным ти- пом T1, если T2 является доменом T1. * Тип указателя Р2, указывающий на объект типа Т3, совместим по присваиванию с типом указателя P1, указывающим на объ- ект T1, если T2 является доменом T1. На этапе компиляции и выполнения выдается сообщение об ошиб- ке, если совместимость по присваиванию необходима, а ни одно из условий предыдущего списка не выполнено.

Раздел описания типов

Программы, процедуры и функции имеют для описания типов спе- циальный раздел описания типов. Например: type TRange = integer; TNumber = integer; TColor = (red,green,blue); TTextIndex = 1..100; TTestValue = -99..99; TTestList = array[TestIndex] of TestValue; PestList = ^TTestList; TDate = object year: integer; month: 1..12; day: 1.. 31; procedure SetDate(D, M, Y: Integer); function ShowDate: String; end; MeasureData = record when: Date; count: TTestIndex; data: TestListPtr; end; TMeasureList = array[1..50] of MeasureData; TName = string[80]; TSex = (male,female); TPersonDate = ^TPersonData; TPersonData = record name,firstName: TName; age: integer; married: boolean; father,child,sibling: Person; case s: Sex of male: (bearded: boolean); female: (pregnant: boolean); end; TPersonDate = array[0..SizeOf(TPersonDate)-1] of Byte; TPeople = file of TPersonData; В этом примере Range, Number и Integer являются тождествен- ными типами. TTestIndex является просто совместимым и совместимым по присваиванию, но не тождественным, с типами Number, Range и Integer. Обратите внимание на использование в описаниях TCharVal и TPersonBuf выражений-констант.
                       Назад | Содержание | Вперед