Краткий справочник по процедурам и функциям object pascal


Содержание

Краткий справочник по процедурам и функциям object pascal

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

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

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

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

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

Описание и вызов процедур и функций

Структура описания процедур и функций до некоторой степени похожа на структуру Паскаль-программы: у них также имеются заголовок, раздел описаний и исполняемая часть. Раздел описаний содержит те же подразделы, что и раздел описаний программы: описания констант, типов, меток, процедур, функций, перменных. Исполняемая часть содержит собственно операторы процедур.

Формат описания процедуры имеет вид:

Формат описания функции:

Формальные параметры в заголовке процедур и функций записываются в виде:

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

Вызов процедуры производится оператором, имеющим следующий формат:

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

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

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

При вызове процедур и функций необходимо соблюдать следущие правила:

  • количество фактических параметров должно совпадать с количеством формальных;
  • соответствующие фактические и формальные параметры должны совпадать по порядку следования и по типу.

Заметим, что имена формальных и фактических параметров могут совпадать. Это не приводит к проблемам, так как соответствующие им переменные все равно будут различны из-за того, что хранятся в разных областях памяти. Кроме того, все формальные параметры являются временными переменными — они создаются в момент вызова подпрограммы и уничтожаются в момент выхода из нее.

Рассмотрим использование процедуры на примере программы поиска максимума из двух целых чисел.

Аналогичную задачу, но уже с использованием функций, можно решить так:

Волгоградский государственный педагогический университет
Кафедра алгебры, геометрии и информатики

Самый сок!

ibigdan в открытом космосе

Справочник Object Pascal

Введение

На текущий момент мы уже умеем создавать приложения Delphi. Тем самым все готово для того, чтобы приступать к изучению языка Object Pascal. Прежде всего, мы ознакомимся с синтаксисом языка — его алфавитом, структурой, ключевыми словами, а так же с правилами составления выражений и типами данных.

Алфавит и словарь языка

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

Прописные и строчные латинские буквы, а так же знак подчеркивания:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z _

0 1 2 3 4 5 6 7 8 9

Пробельные символы (разделители):

Пробел, табуляция, перевод строки, возврат каретки

Составные символы, образуемые сочетанием двух специальных:

ПРИМЕЧАНИЕ
Все прочие символы, включая символы кириллицы, также могут использоваться в Object Pascal, но только внутри строковых переменных и комментариев.

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

Что касается комментариев, то никакого смысла в программе они не несут, и могут использоваться для того, чтобы разработчик мог вставить пояснительный текст в код программы. Комментарии бывают двух видов — однострочные и многострочные. Для однострочных комментариев обычно используют составной символ «//», помещая его перед текстом самого комментария:

// эта строка полностью закомментирована
x=5; // эта часть строки — комментарий

Для многострочных комментариев применяют символы < и >, либо (* и *):

< эти
строки
закомментированы >
(* и эти —
тоже! *)

Комментарии разных типов можно вкладывать друг в друга:

< начало общего комментария
(* этот комментарий был тут раньше *)
// и этот — тоже
а это — последняя строка общего комментария
>

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

Ключевые слова

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

Таблица 3.1. Зарезервированные и ключевые слова в Delphi

Слово Слово Слово Слово
absolute export nil requires
abstract exports nodefault resident
and external not resourcestring
array far object safecall
as file of set
asm finalization on shl
assembler finally or shr
at for out stdcall
automated forward overload stored
begin function override string
case goto package then
cdecl if packed threadvar
class implementation pascal to
const implements private try
constructor in procedure type
contains index program unit
default inherited property until
destructor initialization protected uses
dispid inline public var
dispinterface interface published virtual
div is raise while
do label read with
downto library readonly write
dynamic message record writeonly
else mod register xor
end name reintroduce
except near repeat

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

Переменные и константы

Если ключевые слова имеют заранее предопределенный смысл, то значения констант и переменных определяет программист. Но прежде, чем приступить к исследованию констант и переменных, рассмотрим знак, используемый для некоторых операций, поскольку без этого невозможно дальнейшее продвижение. Речь идет о знаке равенства (=), который используется в Delphi в двух значениях — как оператор присваивания и как оператор сравнения.

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

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

ПРИМЕЧАНИЕ
Более точно выражение можно определить следующим образом: выражение — это набор данных, переменных, операторов и других выражений, которые приводятся к общему значению.

Другой вариант — это использование знака равенства для сравнения 2 операндов. В таком случае он используется самостоятельно:

Такая запись означает, что сравниваются левое (операнд1) и правое (операнд2) значения выражения. Однако специально для констант предусмотрен третий вариант, при котором константе присваивается значение правого операнда (как в случае обычного присваивания), но используется знак равенства без двоеточия:

Таким образом, мы переходим к самим константам и переменным, и начнем мы с констант, как наиболее типичного примера подстановки.

Суть использования констант состоит в том, что вместо какого-либо явного значения указывается его условное обозначение — константа. Допустим, что вы пишете программу, в которой неоднократно следует вычислять НДС. Разумеется, вы можете использовать в выражениях явное значение — 0.18 (18%). Но скорее всего, в программе найдется несколько мест, где в вычислениях требуется значение НДС. Таким образом, если НДС в очередной раз изменят, то вам придется отыскивать в программе все эти строки и вносить правку. В таких случаях на помощь приходят константы — достаточно один раз ее определить, а затем во всех тех местах, где требуется ее значение, указывать имя константы.

Определяются константы при помощи ключевого слова const (от англ. constant):

Теперь во всех выражениях, где требуется значение НДС, просто используется эта константа:

VATsumm := price * VAT;

В этом выражении задействована константа VAT и 2 переменных — VATsumm, которой присваивается значение, и price, которая используется для его вычисления. Впрочем, price в данном случае тоже может быть константой, в отличие от VATsumm. Дело в том, что константы определяются в момент написания программы, а при компиляции в код автоматически подставляются их действительные значения. Соответственно, для вычисляемых значений, равно как и для значений, которые может вводить пользователь, нужны не константы, а переменные. Так, если бы константа VAT была переменной, то можно было бы предусмотреть в программе опцию изменения значения НДС.

Переменные определяются при помощи ключевого слова var (от англ. variable):

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

ПРИМЕЧАНИЕ
Начиная с Delphi 4, в Object Pascal поддерживаются типизированные константы, значения которых можно изменять по ходу выполнения программы. Объявление констант такого типа производится следующим образом: «const : тип = значение». От обычных переменных они отличаются различиями в обработке компилятором, а так же тем, что для них всегда имеется какое-либо предопределенное значение.

Типы данных

Прежде, чем приступить к рассмотрению типов данных, постараемся понять, для чего это вообще надо. Прежде всего, Object Pascal, равно как и его предшественник — язык Pascal, а так же C и C++ относятся к строго типизированным языкам программирования. Типизированные языки, в отличие от нетипизированных (начиная с BASIC и заканчивая различными языками сценариев вроде JavaScript), имеют то преимущество, что уже на этапе синтаксической проверки кода компилятор не допустит заведомо неверных операций. К примеру, вы не сможете сложить строку с числом. Кроме того, типизация положительно сказывается на быстродействии программ: благодаря тому, что компилятор заранее «знает», что за данные ему следует обработать в каждом конкретном случае, он может подбирать оптимальные инструкции при генерации машинного кода.

Теперь рассмотрим собственно типы данных, имеющиеся в Object Pascal. Прежде всего отметим, что они бывают простыми (числа, символы), структурными (массивы, записи), процедурными и вариантными. Знакомство со структурными и процедурными типами мы отложим до соответствующей главы, а пока что перечислим категории простых типов данных:

  • Целочисленные (Integer);
  • Вещественные (Real);
  • Булевы (Boolean);
  • Символьные (Character);
  • Строковые (String).

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

Всего в современных версиях Delphi предусмотрено 7 различных типов данных для целых чисел, все они приведены в таблице 3.2.

Таблица 3.2. Типы целочисленных данных

Тип Диапазон Байт (бит) памяти Отрицательные значения
Byte от 0 до 255 1 (8) Нет
ShortInt от -128 до 127 1 (8) Да
Word от 0 до 65535 2 (16) Нет
SmallInt от -32768 до 32767 2 (16) Да
LongWord от 0 до 4294967295 4 (32) Нет
LongInt от -2147483648 до 21474483647 4 (32) Да
Int64 от -9223372036854775808 до 9223372036854775807 8 (64) Да


ПРИМЕЧАНИЕ
Здесь следует сразу оговориться про понимание памяти в программировании. Так, память считают в байтах. Каждый байт состоит из 8 бит. Бит — это минимальная единица информации, бит может принимать только 2 значения, 0 или 1. Каждая переменная, в зависимости от типа, занимает то или иное количество байт в памяти. Отметим так же, что 2 байта образуют слово (word), а 4 байта — двойное слово.

Помимо перечисленных основных типов, в Delphi имеется еще 2 автоматических целочисленных типа — Integer и Cardinal. Первое, в типичном случае, является синонимом для LingInt, хотя может быть приведено и к типу Int64. Например, если объявит переменную типа Integer и попробовать записать в нее значение, превышающее максимально допустимый размер для типа LongInt, то она автоматически преобразуется в Int64:

var x: integer;
.
x: = 21474483647; // здесь x имеет тип LongInt
x: = x + 1;

Что касается Cardinal, то это — устаревшее определение для LongWord, вы сможете встретить его, если будете просматривать исходные коды, написанные во времена первых версий Delphi. Самым распространенным на практике целочисленным типом данных является Integer.

Перейдем к вещественным типам. Для них так же предусмотрены фиксированные типы (правда, в отличие от целочисленных, их не 7, а 6), и один автоматический. Рассмотрим основные типы в таблице 3.3.

Таблица 3.3. Типы вещественных данных

Тип Диапазон Байт памяти Точность
Single от ±1.5*10^-45 до 3.4*10^38 4 7
Double от ±5.0*10^-324 до 1.7*10^308 8 15-16
Extended от ±3.4*10^-4951 до 1.1*10^4932 10 19-20
Comp от -2^63+1 до 2^63 -1 8 19-20
Currency от -922337203685477.5808 до 922337203685477.5807 8 19-20

Имеется так же и автоматический тип — Real, введенный для совместимости с программами, написанными в Delphi 2 или 3. Сейчас тот тип, что был в ранних версиях Delphi, называется Real48 и практически не используется. Вместо него рекомендуется использовать такие типы, как Single или Double. Если же задать тип Real в программе, то он будет автоматически приведен к типу Double.

Нечто подобное можно сказать и про тип Comp — этот 64-разрядный вещественный тип данных изжил себя с момента появления целочисленного типа Int64, и присутствует лишь в целях совместимости со старым программным кодом.

Зато тип Currency активно используется, особенно при работе с базами данных. Как следует из его названия (Currency — валюта), данный тип предпочтительно использовать для финансовых расчетов. И хотя Currency относится к вещественным типам данных, компилятор обращается с ним как с целым, что позволяет добиться меньших ошибок при округлениях.

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

var
x: integer;
y: double;
.
x := 5;
y := 5.25; // обратите внимание, что дробная часть отделяется точкой
y := x + y; // так делать можно
x := x + y; // а так — нельзя, поскольку результатом должно быть целое

Булевы, или логические типы данных представлены в Delphi типами Boolean, ByteBool, WordBool и LongBool. Все они отличаются только размером памяти, выделяемым для хранения значения, причем значений может быть только 2 — false (ложь) и true (истина):

var x, y: Boolean;
.
x := true;
y := false;

Основным типом является 1-байтовый Boolean (он же ByteBool), 2-байтовый WordBool и 4-байтовый LongBool предусмотрены лишь для совместимости в целях взаимодействия с другими языками и платформами.

Что касается символьных типов данных, то в Delphi предусмотрено 2 их типа — ANSIChar и WideChar. Первый является однобайтовым и может хранить в себе 1 символ из множества символов ANSI, коих насчитывается 256. Второй же тип является 2-байтовым и предназначен для хранения 2-байтовых же символов Unicode. Как и в других случаях, Delphi имеет синоним для символьных типов — Char, который на сегодня является аналогом ANSIChar. Что касается присвоения значений, то обычные символы (буквы и цифры) присваивают переменным символьного типа как есть, лишь заключая их в одиночные кавычки. А специальные символы, например, возврат каретки (Enter) назначают при помощи их номера в таблице ANSI, и выделяют знаком решетки:

var x, y: Char; // x и y получают тип ANSIChar
.
x := a; // обычные символы
y := #13; // возврат каретки в таблице ANSI имеет номер 13

Наконец, еще одним, причем, в общем-то, уже не совсем простым типом данных являются строки. Строковые типы данных отличаются от символьных тем, что могут хранить не единичный символ, а множество символов. В Delphi имеется 3 типа строк: ShortString, AnsiString и WideString. Первый тип строк — ShortString — достался в наследство от языка Pascal и 16-битной Delphi 1.0. Такие строки могут иметь не более 255 символов, и занимают от 2 до 256 байт памяти, в зависимости от размера: Что касается современных строковых типов — AnsiString и WideString, то они могут иметь практически неограниченную длину (AnsiString — до 2 млрд. символов, WideString — до 1 млрд.) и занимать, соответственно, от 4 байт до 2 Гигабайт памяти. При этом по аналогии с символьными типами, тип AnsiString предназначен для хранения обычных строк, а WideString — для строк в формате Unicode. Ну и еще один тип строк — String является синонимом для типа AnsiString:

var str1: ShortString; // короткая строка
var str2: AnsiString; // длинная строка
var str3: String; // тоже длинная строка
.
str1 := Начало.; // Строковые значения заключаются в одинарные кавычки
str2 := Конец.;
str3 := str1 + str2; // получим длинную строку, содержащую Начало.Конец.

В целом, несмотря на кажущееся разнообразие типов данных, на практике чаще всего ограничиваются всего лишь 5-6 основными типами. Это: Integer, Double, Boolean, Char, String, и иногда — еще и Currency.

Данные и значения

Очевидно, что сами по себе типы данных ничего не означают. Главное их предназначение — хранить те или иные значения, или данные. Так, для хранения числовых данных применяют целочисленные или вещественные типы, в зависимости от того, какого типа числа следует использовать. На практике это означает, что будут применяться типы Integer и Double.

ПРИМЕЧАНИЕ
Хотя вещественные типы и являются более универсальными, использовать их надо только при реальной необходимости, поскольку они гораздо менее удобны компьютеру для вычислений. Говоря конкретнее, математические операции над вещественными числами выполняются гораздо медленнее, чем над целыми, а ряд иных операций (например, побитовые, инкремент или декремент) вообще недопустимы.

Строковые данные требуют для своего хранения строковых же типов, т.е. String. Исключение может составить тот случай, когда следует сохранить один и только один символ — в таком случае предпочтительно (а иногда — необходимо) использовать тип Char. Ну а в том случае, если требуется привести какое-то значение к однозначному выводу, используют логический тип Boolean. Например, если сравнивать одно число с другим на предмет того, является ли оно больше, то результатом сравнения будет либо «да», либо «нет», т.е. true или false:

var
x: boolean;
.
x := 5 > 6; // получаем false, т.к. 5 не больше 6

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

Операции и их типы

В любом языке программирования имеются знаки операций. Кроме того, некоторые ключевые слова, например такие, как div или mod также обозначают операции. Все операции в Object Pascal можно разделить на следующие типы: логические, арифметические, логические, операции присвоения и отношения, а так же специальные операции. Для их обозначения используются математические символы или ключевые слова. Участвующие в операциях значения (переменные) называются операндами. При этом та или иная операция может работать с операндами определенного типа. А результатом может быть данные как такого же типа, та и другого (например, для того же сравнения).

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

Операция Название, тип Описание Операнды Результат
+ Сложение, бинарная Возвращает сумму левого и правого операндов integer, real integer, real
Вычитание, бинарная Возвращает разницу левого и правого операндов integer, real integer, real
* Умножение, бинарная Возвращает произведение левого операнда на правый операнд integer, real integer, real
/ Деление, бинарная Возвращает результат деления левого операнда на правый операнд. Результат может быть дробным integer, real real
mod Остаток от деления, бинарная Возвращает остаток от деления левого операнда на правый операнд integer integer
div Деление нацело, бинарная Возвращает целую часть числа, получившуюся в результате деления integer integer
Унарный минус Возвращает число, противоположное операнду integer, real integer, real
+ Унарный плюс Явно указывает знак числа integer, real integer, real

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

Другой распространенный тип операций — логические. В Object Pascal имеются все 4 типа логических операций: не, и, или, исключающее или (таблица 3.5).

Таблица 3.5. Логические операции

Операция Название Описание
not Логическое отрицание (НЕ) Возвращает false, если выражение может быть приведено к истине, в противном случае возвращает true
and Логическое (И) Возвращает true, когда оба выражения истинны. В противном случае возвращает false
or Логическое (ИЛИ) Возвращает true, когда хотя бы одно из выражений истинно. В противном случае возвращает false
xor Логическое (исключающее ИЛИ) Возвращает true, когда только одно из выражений истинно. В противном случае возвращает false

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

not true // возвращает false
not false // возвращает true
true and true // возвращает true
true and false // возвращает false
false and false // возвращает false
true or true // возвращает true
true or false // возвращает true
false or false // возвращает false
true xor true // возвращает false
true xor false // возвращает true
false xor false // возвращает false

Логическому сравнению подлежат не только булевские значения, но и любые другие выражения, которые могут быть к ним приведены. Например, выражение «3=4» может быть использовано в качестве логически сравниваемой единицы, поскольку результатом его оценки будет булево значение ложь (false).

Те же самые знаки операций, что используются в логических операциях, задействованы и в другом типе операций — побитовых. Побитовые операции выполняются над числами, представленными в двоичном виде (т.е. только нули и единицы). Однако сами операнды могут быть десятичными, шестнадцатеричными, или восьмеричными целыми числами. Например, десятичное число 5 представляется как двоичное 101, десятичное 6 — как 110, а шестнадцатеричное F3 — как двоичное 11110011.

Хотя побитовые операции выполняются над двоичными данными, возвращаемые значения являются стандартными числами. Список всех побитовых операций приводится в таблице 3.6.

Таблица 3.6. Побитовые операции

Операция Название Описание
and Побитовое И Возвращает число, являющееся результатом побитового сравнения «И»
or Побитовое ИЛИ Возвращает число, являющееся результатом побитового сравнения «включающее ИЛИ»
xor Побитовое исключающее ИЛИ Возвращает число, являющееся результатом побитового сравнения «исключающее ИЛИ»
not Побитовое НЕ Возвращает число, с битами, расположенными в обратном порядке
shl Сдвиг влево Сдвигает первый операнд влево на число разрядов, заданных вторым операндом. Освобождающиеся правые биты заполняются нулями
shr Сдвиг вправо Сдвигает первый операнд вправо на число разрядов, заданных вторым операндом. Освобождающиеся левые биты отбрасываются

Чтобы явно представить себе, как работают побитовые операции, обратимся к следующему примеру. Допустим, имеется 2 переменных — x и y:

var x, y: integer;
.
x := 3;
y := 5;

В двоичном представлении число 3 будет выглядеть как 0011, а 5 — как 0101. Теперь посмотрим, какие результаты даст каждая из побитовых операций сравнения и операции отрицания над этими числами:

x or y // Получим 7: 0011 | 0101 = 0111
x and y // Получим 1: 0011 & 0101 = 0001
x xor y // Получим 6: 0011 ^ 0101 = 0110
not x // Получим 12:

Илон Маск рекомендует:  Что такое код setscrollrange

Что касается операций побитового сдвига, то они дадут следующие результаты:

y shl 2 // Получим 20: 0101 shl 2 = 10100
y shr 2 // Получим 1: 0101 shr 2 = 01
-y shr 2 // Получим -2: -0101 shr 2 = -10

Теперь нам остается исследовать еще один тип операций — операции сравнения. Эти операции всегда требуют наличия двух операндов: они сравнивают значения левого и правого операндов, и возвращают результат сравнения в виде логического значения, которое может принимать значение false или true (ложь или истина). Все имеющиеся в Object Pascal операции сравнения приведены в таблице 3.7.

Таблица 3.7. Операции сравнения

Операция Название Описание Пример, дающий true
= Равно Возвращает истину (true), когда левый и правый операнды равны. 1=1
<> Не равно Возвращает истину, когда левый и правый операнды не равны. 1<>2
> Больше Возвращает истину, когда левый операнд больше правого. 2>1
= Больше или равно Возвращает истину, когда левый операнд больше правого или равен ему. 1>=0; 1>>1
var
x: Char;
z: Boolean;
.
x := ‘b’;
z := x in [a..d];

В данном случае в качестве результата (z) мы получим истину, поскольку символ b является членом указанного множества [a..d], в которое входят символы a, b, c и d.
Наконец, в Object Pascal имеется еще 2 операции — as и is. Они служат для приведения типа и проверки типа, соответственно. Например, если мы хотим проверить, является ли некая переменная «x» целым, то можно написать такое выражение:

b := x is Integer; // b получит значение true, если x — целое

Ну а операция as используется для приведения данных одного типа к другому, причем, преимущественно, при работе с объектами:

При использовании операции as следует быть осторожным, поскольку приведение одного типа к другому возможно далеко не всегда.

Выражения и приоритет операций

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

a := b + c;
d := e * f;
g := a — d div 2;

Так же, как и в обычной математике, при составлении выражений в Object Pascal, следует учитывать приоритет выполнения операций. Например, операции умножения или деления должны выполняться раньше, чем сложение и вычитание. Так, в 3-й строке из приведенных выше примеров выражений, согласно математическим правилам, сначала выполняется операция деления нацело (d div 2), затем результат этой операции вычитается из a, и итоговое значение присваивается переменной g. Все те же правила действуют и в программировании, но поскольку перечень операций не ограничивается арифметическими, а в рамках одного выражения могут быть использованы различные типы операций, то было бы неплохо внести полную ясность в этот вопрос.

Прежде всего, приоритет выполнения определяется принадлежностью конкретной операции к тому или иному типу. Так, первыми выполняются унарные операции, затем — операции умножения (включая деление и побитовые), далее обрабатываются сложение и вычитание (опять, таки включая побитовые or и xor), и, наконец, в последнюю очередь — операции отношения. Для удобства представим все операции, классифицированные по уровню приоритета, в виде таблицы (табл. 3.8).

Таблица 3.8. Приоритет выполнения операций

Операторы Уровень приоритета Категория
@, not Высший Унарные
*, /, div, mod, and, shl, shr, as Высокий Умножение
+, -, or, xor Средний Сложение
=, <>, >, =, in, is Низкий Отношение

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

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

Таким образом, сначала здесь из a вычитается d, и лишь затем производится операция деления нацело.

Структура программы

Теперь, когда мы уже знаем об основных языковых конструкциях языка — «словах» (ключевые слова, переменные, операторы и т.д.) и выражениях, рассмотрим, как все это объединяется в общий код программы.

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

program ;
uses ;
label ;
const ;
type ;
var ;
;
begin
;
end.

В структуре той или иной программы часть этих разделов может быть опущена за ненадобностью. Обязательными являются всего 3 ключевых слова — program (вместе с названием), а так же begin и end. Разумеется, между begin и end должны находиться какие-либо инструкции. Так, возвращаясь к примеру «Hello, World», в нем можно обнаружить лишь название программы и блок инструкций:

program hello; // название
<$APPTYPE CONSOLE>//это указание компилятору к коду программы не относится
begin // начало исполняемого кода
write(Hello, World!); // инструкции
readln;
end. // конец программы

ПРИМЕЧАНИЕ
Список модулей в данном случае не нужен, поскольку мы не используем никаких дополнительных функций или процедур из библиотеки Object Pascal. Но, разумеется, в более сложных программах они могут понадобиться.

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

Рассмотренная нами структура характерна для программ на Pascal в целом, в том числе и для Windows-приложений, разрабатываемых визуальными средствами. Структура же отдельных модулей, представляющих собой описание того или иного окна, имеет ряд отличий. В общих чертах ее можно представить следующим образом: начинается такой модуль с ключевого слова unit, после которого следуют секции interface и implementation. Иногда могут быть также использованы еще 2 секции — initialization и finalization. Ну а завершается все это, разумеется, ключевым словом end с точкой:

unit ;
interface

implementation
;
initialization
;
finalization
;
end.

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

Завершая эту тему, затронем еще один аспект структуры программ — подпрограммы. В качестве подпрограммы понимается блок инструкций, предназначенный для решения какой-либо частной задачи в рамках самой программы. Такие блоки в Object Pascal могут просто выполняться — в таком случае они называются процедурами, либо выполняться и возвращать какой-либо результат — в таком случае они называются функциями. И в том, и в другом случае, они могут принимать какие-либо значения для обработки. Эти значения называются аргументами. В целом же синтаксис обращения к процедуре или функции выглядит следующим образом:


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

Операторы Object Pascal

Знание синтаксиса языка лишь теоретически позволяет приступить к созданию программ. Дело в том, что важнейшей частью любого языка программирования, во многом определяющими удобство составления алгоритмов, являются его управляющие структуры — операторы, или инструкции.

Об управляющих структурах

В реальных программах выполнение операций не бывает строго последовательным: постоянно требуются различные переходы, ветвления, повторения и т.д. Операторы бывают простыми (например X := 5;) или составными. Составной оператор представляет собой группу из произвольного числа любых инструкций, ограниченных ключевыми словами begin и end:

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

Условный оператор if

Пожалуй, самой важной инструкцией для управления выполнением программы является условный оператор if. Именно он отвечает за ветвление, т.е. выполнение (или невыполнение) того или иного варианта кода в зависимости от условий. Оператор if используется совместно с ключевым словом then, а в том случае, когда предусмотрен альтернативный вариант выполнения — еще и с else. В целом синтаксис инструкции получается следующим:

В качестве условия может быть использовано любое выражение, которое может быть приведено к булевскому значению, т.е. к false или true. Как правило, это бывают операции сравнения, например:

if a > 5 then b := 10;
if x <> 0 then y := 1 else y :=2;

В первом случае, если переменная a больше 5, то переменной b будет присвоено значение 10, если же a меньше или равно 5, то ничего выполнено не будет и управление будет передано следующему выражению. Во второй строке переменная x проверяется на ненулевое значение, и если x окажется числом, отличным от 0, то переменной y будет присвоено значение 1, в противном случае (если x равно 0) переменной y будет присвоено значение 2.

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

if a > 5 then
begin
b := 10;
c := 20;
end;

Как мы уже знаем, в соответствии с правилами синтаксиса Object Pascal, все то, что помещено между ключевыми словами begin и end, равно как и сами эти слова, воспринимаются как 1 оператор. Обратите внимание, что в конце поставлен пустой оператор — точка с запятой. В данном случае по правилам синтаксиса он здесь не обязателен, однако будет хорошим тоном завершать им каждый составной оператор, чтобы выделить тем самым окончание той инструкции, в которой он был применен. В данном случае получается, что мы использовали 2 оператора — составной и пустой, однако нарушения синтаксиса тут нет — компилятор сочтет, что пустой оператор следует уже после условного. Но если бы мы использовали еще и блок else, это привело бы к ошибке синтаксиса, поскольку между then и else допустима лишь 1 инструкция. Поэтому в таком случае точку с запятой следует разместить уже после оператора, следующего за else:

if a > 5 then
begin
b := 10;
c := 20;
end
else
begin
b := 20;
c := 15;
end;

В тех случаях, когда требуется предусмотреть 3 или более вариантов исполнения, используют вложение операторов if друг в друга. Например, если требуется выполнить один вариант когда, когда некая переменная x меньше нуля, другой — если x равна 0, и третий — если x больше нуля, то синтаксис операторов может быть следующим:

if x else
if x = 0 then else 0>;

В данном случае использован вложенный оператор if, который выполняется в случае, когда переменная x не меньше 0. Он проверяет, не является ли значением x число 0, и если нет, то, учитывая, что x явно не меньше, чем 0 (это условие к моменту выполнения вложенного оператора if уже проверено внешним, т.е. первым в данном выражении оператором if), значит значение x больше 0.

Оператор выбора case

Условный оператор удобен в тех случаях, когда необходимо проверить 1-2-3 варианта. При большем числе получается слишком громоздкая и неудобная для восприятия конструкция из множества вложенных инструкций. Скажем, если требуется проверить 5 значений переменной x, то получим такую конструкцию:

if x = 1 then ;
else if x = 2 then ;
else if x = 3 then ;
else if x = 4 then ;
else if x = 5 then ;

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

case [выражение-селектор] of
: ;
: ;
.
: ;
[else ;]
end

Единственным ограничением семафора, в сравнении с условным оператором, является то, что в качестве селектора могут выступать лишь данные порядкового типа, скажем, целым числом или же символом. Впрочем, для подавляющего числа случаев этого достаточно. Например, приведенный выше вариант кода с 4 вложенными условными операторами, при помощи case можно оформить так:

Здесь подразумевается, что типом переменной x является целое число, поскольку тип значений, коими в данном случае являются целые числа, должен соответствовать типу селектора.

Инструкция выбора выполняется следующим образом: вначале, при необходимости, вычисляется значение селектора, затем производится последовательный обход вариантов на предмет совпадения с селектором. В случае совпадения, выполняется инструкция, предусмотренная для этого варианта, после чего выполнение оператора выбора заканчивается. Если же ни один из перечисленных вариантов не совпал со значением селектора (для нашего случая — если x меньше 1 или больше 5), то либо оператор завершается без каких-либо действий, либо, при наличии блока else, выполняются заданные в нем инструкции.

В качестве констант выбора могут выступать не только единичные значения, но и их список, разделенный запятыми, или же диапазоны, определенные границами из 2 констант, разделенных двумя точками. В таком случае мы можем объединить логически связанные значения в группы, для которых следует выполнить один и тот же код. Например, таким образом можно получить название времени года в зависимости от порядкового номера месяца (листинг 4.1).

Листинг 4.1. Использование оператора case

var
month: integer;
season: string;
.
case month of
1,2,12: season := «зима»;
3..5: season := «весна»;
6..8: season := «лето»;
9..11: season := «осень»;
else season := «других не знаем!»;
end;

В данном случае, если переменная month имеет значения 1, 2 или 12, то переменной season присваивается значение «зима», если же значение переменной month окажется в диапазоне от 3 до 5 (включительно), то season получит значение «весна», и т.д.

Оператор цикла for

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

for := to do ;
for := downto do ;

В первом случае (с использованием цикла for-to) при каждом проходе цикла, называемом итерацией, значение параметра увеличивается на 1, а во втором (for-downto) — уменьшается на 1. При этом в качестве начального значения используется «выражение 1», а в качестве конечного — «выражение 2». Разумеется, если для цикла to значение первого выражения изначально будет больше значения второго, или наоборот, меньше (для цикла downto), то цикл не будет выполнен ни разу.
Практическое применение циклов крайне разнообразно. Если привести наиболее общий пример из программирования, то цикл — идеальный способ заполнения массива. Например, если требуется организовать цикл для заполнения массива из 10 числовых значений последовательно возрастающими числами, то можно записать:

for i := 0 to 9 do MyArray[i]=i;

В данном случае элементам массива MyArray последовательно назначаются значения от 0 до 9.

ПРИМЕЧАНИЕ
Сами массивы будут рассмотрены несколько позже, в главе, посвященной структурным типам данных.

Теперь рассмотрим цикл for с отрицательным приращением на примере вычисления математического факториала (последовательное произведение всех целых чисел от 1 до самого числа). Для этого нам понадобится следующий цикл:

var num, rez: integer;
.
rez := 1;
for num := num downto 1 do rez := rez * num;

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

В итоге, если переменной num присвоить значение 5, то после прохождения цикла переменная rez получит значение 120. Хотя в результате работы такого цикла получится выполнение как бы наоборот (т.е. не вместо 1*2*3*4*5, на самом деле выполняется 5*4*3*2*1), это никак не помешает получить верный результат.

Наконец, в качестве тела цикла, как и в случае с уже рассмотренными операторами, может использоваться составной оператор. Кроме того, циклы могут быть вложены один в другой, при этом важно лишь следить за тем, где заканчивается вложенный цикл и начинается внешний. Для этого полезно следить за правильным оформлением программы, в частности, использовать отступы, в качестве которых можно использовать либо знак табуляции, либо пробелы, в последнем случае их желательно ставить не менее 2 (листинг 4.2).

Листинг 4.2. Вложенные циклы и форматирование кода

for x := 5 to 10 do begin
z := x;
for y := 10 to 20 do begin
z := z + x * y;
writeln(z);
end; // конец вложенного цикла
writeln(x);
end; // конец внешнего цикла

При использовании циклов с параметром важно помнить, что изменение значения параметра в теле цикла недопустимо.

Операторы циклов while и repeat

Помимо классического цикла с параметром, в Object Pascal предусмотрено еще 2 вида циклов — с предусловием и с постусловием. В качестве цикла с предусловием выступает оператор while. Он имеет следующий синтаксис:

Этот цикл будет выполняться до тех пор, пока верно выражение, указанное в качестве условия. Соответственно, если значение выражение будет изначально ложным, то цикл не будет выполнен ни разу, например:

while false do ;
В то же время, при помощи оператора while удобно делать бесконечный цикл. В бесконечных циклах весь контроль возлагается на операторы, помещаемые в тело цикла:
while true do begin

end;

ПРИМЕЧАНИЕ
Очевидно, что цикл с условием, которое изначально истинно и никак не изменяется, будет выполняться вечно. Таким образом, в теле цикла следует предусмотреть возможность его прерывания иным способом.

В отличие от while, цикл с постусловием, задаваемый при помощи оператора repeat, всегда выполняется хотя бы 1 раз, поскольку проверку на соответствие условию он проходит после того, как будет выполнено его тело:

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

repeat
x := x + 1;
y := x * 2;
until y

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

Операторы break и continue

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

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

while true do begin
a := b * c;
if a > 1000 then break;
b := b + 1; // в случае если a > 1000, эта строка выполнена не будет
end;
Еще одним полезным применением досрочного выхода является его использования в качестве дополнительного параметра. Например, если нам нужен цикл, который должен прерваться по 1 из 2 условий, то для второй проверки мы можем использовать условный оператор if совместно с break:
repeat
i := i + 1;
if i > 100 then break;
y := y — 1;
until y

Здесь мы определили цикл, который будет завершен либо после того, как значение переменной y достигнет 50 (что задано в самом условии цикла), либо если значение переменно x превысит указанное в условии if значение 100 — здесь как раз будет задействован оператор break.

Иногда бывает необходимо перейти к следующему шагу цикла досрочно, пропустив часть операторов. Для этих целей используют оператор continue. В отличие от break, этот оператор не завершает цикл, а заставляет программу досрочно перейти к новой проверке условия цикла. Рассмотрим эту ситуацию на примере. Допустим, что нам надо получить список чисел, на которые число 100 делится без остатка:

for i := 1 to 100 do begin
if 100 mod i <> 0 then continue;
writeln(i);
end;

Для этого мы определили цикл, в котором при каждой итерации делитель, в качестве которого выступает счетчик цикла, увеличивается на единицу. В самом теле цикла использован условный оператор, в котором условием выступает выражение, в котором производится операция «остаток от деления» и ее результат сравнивается с 0. Таким образом, если дано условие истинно (т.е. если остаток равен нулю), то интерпретатор переходит к следующему оператору в теле цикла, который выводит нужное нам число, в противном случае выполняется оператор continue и начинается новый шаг цикла.

Краткий справочник по процедурам и функциям object pascal

Решил в краткой и одновременно в более понятной форме изложить основы Object Pascal. Тем не менее, здесь всего лишь минимум и для большего объема я советую Вам прочитать книгу «Библия для программистов в среде Delphi».

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

Модули — это программные единицы, предназначенные для размещений фрагментов программ. Следующий фрагмент программы является синтаксически правильным вариантом модуля:

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

Элементы программы — это минимальные неделимые ее части, еще несущие в себе определенную значимость для компилятора. К элементам относятся:

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

Стандартные директивы первоначально связаны с некоторыми стандартными объявлениями в программе. К ним относятся:

Типы — это специальные конструкции языка, которые рассматриваются компилятором как образцы для создания других элементов программы, таких как переменные, константы и функции.

Основные типы данных


К основным типам данных языка Delphi относятся:

целые числа (integer);
дробные числа (real);
символы (char);
строки (string);
логический тип (boolean).

Целые числа и числа с плавающей точкой могут быть представлены в различных форматах.

В версиях Delphi 4 и 5 тип Real эквивалентен типу Double. Если требуется (в целях совместимости) использовать 6-байтный Real, нужно указать директиву компилятора .

Массивы в Object Pascal во многом схожи с аналогичными типами данных в других языках программирования. Отличительная особенность массивов заключается в том, что все их компоненты по сути данные одного типа. Эти компоненты можно легко упорядочить и обеспечить доступ к любому из них простым указанием его порядкового номера. Описание типа массива задается следующим образом:

В качестве индексных типов в Object Pascal можно использовать любые порядковые типы, имеющие объем не более 2 Гбайт (т. е. кроме LongWord И Int64).

Определить переменную как массив можно и непосредственно при описании этой переменной, без предварительного описания типа массива, например:

С версии Delphi 4 впервые введены так называемые динамические массивы. При объявлении таких массивов в программе не следует указывать границы индексов:

В этом примере динамический массив А имеет одно измерение, массив В — два и массив С — три измерения. Распределение памяти и указание границ индексов по каждому измерению динамических массивов осуществляется в ходе выполнения программы путем инициации массива с помощью функции SetLength. В ходе выполнения такого оператора:

одномерный динамический массив A будет инициирован, т. е. получит память, достаточную для размещения трех целочисленных значений. Нижняя граница индексов по любому измерению динамического массива всегда равна 0, поэтому верхней границей индексов для A станет 2.

Объявление одномерного массива:

Объявление двумерного массива:

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

Структура объявления типа записи такова:

Вариант 1. Объявление записи в разделе переменных:

Вариант 2. Сначала объявляется тип-запись, затем — переменная-запись:

Множества — это наборы однотипных логически связанных друг с другом объектов. Характер связей между объектами лишь подразумевается программистом и никак не контролируется Object Pascal. Количество элементов, входящих в множество, может меняться в пределах от 0 до 255 (множество, не содержащее элементов, называется пустым). Именно непостоянством количества своих элементов множества отличаются от массивов и записей.

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

Описание типа множества имеет вид:

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

Указатель — это переменная, которая в качестве своего значения содержит адрес байта памяти. С помощью указателей можно размещать в динамической памяти любой из известных в Object Pascal типов данных. Лишь некоторые из них (Byte, Char, ShortInt, Boolean) занимают во внутреннем представлении один байт, остальные — несколько смежных. Поэтому на самом деле указатель адресует лишь первый байт данных.

Как правило, указатель связывается с некоторым типом данных. Такие указатели будем называть типизированными.

Объявление переменной-строки длиной 255 символов: Имя: string;

Объявление переменной-строки указанной длины: Имя: string [ ДлинаСтроки ].

В Object Pascal определены следующие логические операции:

not — логическое НЕ;
and — логическое И;
or — логическое ИЛИ;
xor — исключительное ИЛИ.
К логическим же в Object Pascal обычно относятся и две сдвиговые операции над целыми числами:

i shl j — сдвиг содержимого i на j разрядов влево; освободившиеся младшие разряды заполняются нулями;

i shr j — сдвиг содержимого i на j разрядов вправо; освободившиеся старшие разряды заполняются нулями.

Правила использования операций с операндами различного типа.

Составной оператор — это последовательность произвольных операторов программы, заключенная в операторные скобки — зарезервированные слова begin . end . Составные операторы — важный инструмент Object Pascal, дающий возможность писать программы по современной технологии структурного программирования (без операторов перехода goto).

Вариант 1: if-then-else.

Вариант 2: if-then.

Примечание: если между begin и end находится только одна инструкция, то слова begin и end можно не писать.

Инструкции между begin и end выполняются, если значение выражения, записанного после case, совпадает с константой из соответствующего списка. Если это не так, то выполняются инструкции, находящиеся после else, между begin и end.

Примечание: если между begin и end находится только одна инструкция, то слова begin и end можно не писать.

Вариант 1 (с увеличением счетчика):

Если НачальноеЗначение > КонечноеЗначение, то инструкции между begin и end не выполняются.

Примечание: если между begin и end находится только одна инструкция, то слова begin и end можно не писать.

Вариант 2 (с уменьшением счетчика):

Если НачальноеЗначение Объявление функции

Примечание: слово var ставится перед именем параметра в том случае, если параметр используется для возврата значения из функции в вызвавшую ее программу.

Примечание: слово var ставится перед именем параметра в том случае, если параметр используется для возврата значения из процедуры в вызвавшую ее программу.

Национальная библиотека им. Н. Э. Баумана
Bauman National Library

Персональные инструменты

Object Pascal

Object Pascal
Парадигма мультипарадигмальный: императивный, структурный, объектно-ориентированный, обобщённый, процедурный
Спроектировано Ларри Теслер, Никлаус Вирт
Первый появившийся 1986
Печать дисциплины статическая, динамическая (array of const, RTTI, Variant), строгая
Расширение файла .p, .pp, .pas
Главная реализация
Delphi (x86 and CLI), Oxygene (CLI), Free Pascal (x86, x86-64, PowerPC, ppc64, SPARC and ARM), Virtual Pascal (x86), TMT Pascal (x86), Turbo51 (Intel 8051)
Диалект
Apple, Turbo Pascal, objfpc, Delphi, Delphi.NET, Oxygene
Под влиянием
Паскаль, Smalltalk
Влияние
C#, Java

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

Object Pascal имеет свои особенности, которые поддерживают структуру компонентов Delphi и RAD окружения.

Содержание

История

Object Pascal является расширением языка Pascal, который был разработан в Apple Computer командой во главе с Ларри Теслер с Никлаус Вирт, изобретателем языка Паскаль. Object Pascal происходит от более ранней объектно-ориентированной версии Паскаля называемой Clascal, который был доступен на Lisa компьютере.

Object Pascal, был необходим для поддержки МасАрр, расширяемой инфраструктуры приложений Macintosh, которая теперь называется библиотекой классов. Object Pascal и сам МасАрр были разработаны Барри Хайнс, Кен Дойл, и Ларри Розенштейна, и были протестированы Дэнем Алленом. Ларри Теслер курировал проект, который запустился в 1985 году и стал продуктом в 1986 году.

Object Pascal был также реализован в Think Pascal IDE. Среда IDE включает в себя компилятор, редактор с подсветкой синтаксиса, проверку синтаксиса, мощный отладчик и библиотеки классов.

Компания Apple отказалась от поддержки Object Pascal, когда они перешли на архитектуру PowerPC от IBM в 1994 году. МасАрр 3.0, для новой платформы, была переписана на С ++.

Токены

Токены — это основные лексические блоки исходного кода: они являются «словами» языка: символы объединяются в токены в соответствии с правилами языка программирования. Есть пять классов лексем:

  1. Зарезервированные слова. Эти слова, которые имеют постоянное значение в языке. Они не могут быть изменены.
  2. Идентификаторы. Эти имена символов, которые программист определяет самостоятельно. Они могут быть изменены и использоваться повторно. Они подчиняются правилам области видимости языка.
  3. Операторы. Это, как правило, символы математических операций или других: +, -, * и так далее.
  4. Разделители. Это, как правило, пробелы.
  5. Константы. Численные или символьные константы используются для обозначения фактических значений в исходном коде. Например, 1 (целая константа) или 2.3 (константа с плавающей точкой) или “Строка константа” (строка: часть текста).

Комментарии

Free Pascal поддерживает использование вложенных комментариев. Следующие конструкции являются допустимыми комментарии:

Структурные операторы

Структурированные операторы построены из других операторов. Используйте структурированный оператор, когда вы хотите выполнить действия последовательно, по условию, или несколько раз.

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

Параметры

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

В этом случае параметр используется для передачи значения по ссылке и происходит возврат нового значения после вызванной процедуры. Если вы пишите:

Значение переменной X станет равно 20, потому что функция использует ссылку на X, влияющую на его первоначальное значение. Передача параметров по ссылке имеет смысл для порядковых типов, для старомодных строк, так и для крупных записей. Объекты Delphi, на самом деле, неизменно передаются по значению, потому что они являются ссылками. По этой причине, в передаче объекта по ссылке мало смысла (кроме особых случаев), так как это соответствует передаче «ссылке по ссылке»

Параметры-константы

Варианты

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

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


Концепции объектно-ориентированного программирования

В Паскале есть два структурных типа данных, используемых для реализации объекта в реальном мире —

Прежде чем перейти к деталям, нужно определить термины Pascal, связанные с объектно-ориентированным Pascal.* Object — Объект представляет собой особый вид записи, который содержит поля, такие как записи; Однако, в отличие от записи, объекты также содержат процедуры и функции, являющиеся частью объекта. Такие процедуры и функции рассматриваются как указатели на методы, связанные с типом объекта.

  • Класс — Класс определяется почти так же, как объект, но есть разница в способе их создания. Класс выделяется в куче программы, в то время как объект выделяется на стеке. Класс является указателем на объект, а не самим объектом.
  • Создание экземпляров класса — означает создание переменной этого типа класса. Поскольку класс является просто указателем, когда переменная типа класса объявляется, тогда выделяется память только для указателя, а не для всего объекта. Память выделяется для объекта, только когда экземпляр использует один из его конструкторов. Экземпляры класса также называются «объектами», но не путайте их с Object Pascal объектами. Мы будем писать «объект» для Pascal Object и «объект» для экземпляра концептуального объекта или класса.
  • Переменные-члены — Это переменные, определенные внутри класса или объекта.
  • Функции-члены — Это функции или процедуры, определенные внутри класса или объекта и используются для доступа к данным объекта.
  • Видимость членов — члены объекта или класса также называют полями. Эти поля имеют различные уровни видимости. Видимость относится к доступности членов, т.е. именно там, где эти члены будут доступны для обращения. Объекты имеют три уровня видимости: public, private and protected. Классы имеют пять типов Видимость: public, private, strictly private, protected and published.
  • Наследование — Когда класс определяется путем наследования существующего функционала родительского класса, то говорят, он наследуется. В этом случае дочерний класс наследует все или несколько функций-членов и переменных родительского класса. Объекты могут также быть унаследованы.
  • Родительский класса — класс, который передается по наследству другому классу. Он также называется базовым классом или супер классом.
  • Дочерний класс — класс, который наследуется от другого класса. Он также называется подклассом или производным классом.
  • Полиморфизм — это объектно-ориентированная концепция, в которой утверждается, что функция может быть использована для различных целей. Например, имя функции будет оставаться таким же, но она может требовать разное количество аргументов и может выполнять различные действия. Pascal классы реализуют полиморфизм. Объекты не реализовывают полиморфизма.
  • Перегрузка — это тип полиморфизма, в котором все или несколько операторов имеют разные реализации в зависимости от типов их аргументов. Аналогично могут быть перегружены и функции с различной реализации. Pascal классы реализуют перегрузки в отличии от объектов .
  • Абстракция данных — Любое представление данных, где скрыты детали реализации (если абстрагироваться).
  • Инкапсуляция — относится к концепции ООП, где происходит инкапсуляция всех функций данных и членов вместе, чтобы сформировать объект.
  • Конструктор — относится к специальному типу функции, которая будет вызвана автоматически, когда будет формироваться объект из класса или объекта.
  • Деструктор — относится к специальному типу функции, которая будет вызвана автоматически, когда объект или класс будет удален или выйдет из области видимости.

Видимость членов объекта

Примеры программ «Hello World»

Apple, Object Pascal

Turbo Pascal, Object Pascal

Тем не менее поддерживается в Delphi и Free Pascal. FPC также упаковывает свои заменители для библиотек / модулей. Delphi этого не делает. Free Pascal 1.0 и IDE FPC являются крупнейшими открытыми базами кода в этом диалекте. Free Pascal 2.0 была переписана в Delphi как диалект, а IDE и связанные с ним структуры (Free Vision) являются единственными частями в TP версии Object Pascal.

Delphi и Free Pascal, Object Pascal

Обратите внимание, что объект «конструкция» по-прежнему доступен в Delphi и Free Pascal (Delphi-совместимый режим).

Oxygene Object Pascal

Следует отметить, что реализация метода также может быть выполнена в отдельном месте, как и в других Object Pascal диалектах.

#14 Процедуры и функции в Паскаль. Как объявлять и использовать

Primary tabs

Forums:

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

Чем процедуры отличаются о функций

Различия между процедурами и функциями в Паскаль:

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

Сигнатура процедур и функций

Процедуры и функции принимают какие-то значения «на вход» — это те данные, с которыми процедура или функция будут работать.

Сигнатура — характеристика функции, которая говорит о том, что нужно передавать в функцию и на результат какого типа следует рассчитывать после её выполнения.
Или, если речь идёт о процедуре — то просто «данные каких типом нужно передать в процедуру, чтобы она сработала»

Вызов процедуры и её сигнатура

Сигнатура процедуры определяется:

  1. Именем процедуры
  2. Числом, типом входящих переменных и их порядок следования

Например, рассмотрим реализацию процедуры $sum1()$, которая складывает два числа и выводит сумму на экран:

Иллюстрацией к сигнатуре этой процедуры служит её заголовок:

— где фактически написано, что для нормальной работы этой процедуре требуется получить (а программисту во внешнем коде передать) два значения целого типа, рассмотрим пример вызова этой процедуры с передачей параметров:

Вызов функции и её сигнатура

Сигнатура функции определяется:

  1. Именем функции
  2. Числом, типом входящих переменных и их порядок следования
  3. Типом возвращаемого значения

Процедуры

Рассмотрим пример программы с процедурой:

  • переменная $z$ в процедуру $sum()$ передана по ссылке, это значит, что если её изменить в теле процедуре, то она изменится и в том месте, откуда её передали в процедуру (например, в теле основной программы).
  • Переменные же $x$ и $y$ переданы по значению — это надо понимать так, что если их значения будут изменяться внутри процедуры (в данном случае), то «снаружи» эти изменения видны не будут.

Функции

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

Примеры кода — разбор решений

Пример №1 — функция не принимающая аргументов

Напишите функцию, которая не принимает аргументов и возвращает число $55$

Пример №2 — функция: входящие аргументы разного типа, локальные переменные подпрограммы

Напишите функцию, которая принимает два аргумента: первый целого типа, а второй вещественного, и возвращает разницу между их произведением и их суммой.

Решение:

Задачи для самостоятельного решения

  1. Напишите функцию, которая возвращает сумму трёх целых чисел.
  2. Напишите процедуру, которая выводит на экран сумму трёх целых чисел.
  3. Напишите процедуру, которая принимает переменную целого типа по ссылке, просит пользователя ввести значение в консоли и инициализирует переменную этим значением (убедитесь, что в теле программы значение изменилось).

Источники и полезные материалы:

Pascal-Паскаль

Программирование. Стандартные функции Pascal-Паскаль

  • Скачено бесплатно: 6855
  • Куплено: 414
  • Pascal-Паскаль->Программирование. Стандартные функции Pascal-Паскаль

Программирование. Стандартные функции Pascal-Паскаль

Стандартные функции Pascal-Паскаль

Стандартные математические функции Турбо Паскаля
Обращение Тип аргумента Тип результата Примечание
Abs(x) Real, integer Тип аргумента Модуль аргумента
ArcTan(x) Real, integer Real Арктангенс (значение в радианах)
Cos(x) Real, integer Real Косинус, угол в радианах
Exp(x) Real, integer Real Экспонента
Frac(x) Real Real Дробная часть числа
Int(x) Real, integer Real Целая часть числа
Ln(x) Real, integer Real Логарифм натуральный
Pi Нет Real 3,141592653
Sin(x) Real, integer Real Синус, угол в радианах
Sqr(x) Real, integer Тип аргумента Квадрат аргумента
Sqrt(x) Real, integer Real Корень квадратный
Random Нет Real Псевдослучайное число в интервале [0, 1]
Random(I) Integer Integer Псевдослучайное число в интервале [0, I]
Round(x) Real Integer Округление до ближайшего целого
Trunc(x) Real Integer Отбрасывание дробной части числа

Порядок вычислений в выражениях следующий:

  1. вычисляются подвыражения, заключенные в скобки;
  2. затем выполняются операции с наибольшим приоритетом; обычно используются следующие уровни приоритетов (в порядке убывания):
    • возведение в степень;
    • мультипликативные операции: * , / , div , mod;
    • унарные операции: + , — , abs , not;
    • аддитивные операции: +, -;
    • операции отношения: = , <>, , =;
    • логические операции: and, or, not;
  3. операции с одинаковым приоритетом выполняются слева направо.

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


  • в Паскале нет стандартной операции или стандартной функции возведения в степень, поэтому используется следующее математическое тождество: x y = e ylnx
  • в Паскале существует только стандартная функция вычисления натурального логарифма, поэтому используется следующее математическое тождество: logab= ln b/ln a

Математическое выражение: x 3/2 — 7x + tg (x+2)

Выражение на Паскале: exp(3*ln(x)/2)-7*x+sin(x+2)/cos(x+2)

Операторы действия

Операторы действия — это средства языка, позволяющие изменять в процессе выполнения программы состояние вычислений. Самый простой оператор действия — оператор присваивания.

Пример оператора присваивания

Оператор присваивания, несмотря на кажущуюся простоту, имеет очень важное алгоритмическое значение.

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

  1. В каждый момент времени в ящике может храниться не более одного значения.
  2. Каждый ящик способен хранить только значения одного и того же типа. Попытка поместить в ящик значение любого другого типа приводит к тому, что ящик отказывается принимать на хранение передаваемое ему значение — это расценивается как ошибка в программе.
  3. Значение, помещенное в ящик, будет храниться в нем до тех пор, пока в этот ящик не будет помещено новое значение (в момент присваивания соответствующей переменной этого нового значения) — при этом предыдущее содержимое ящика безвозвратно теряется (уничтожается).
  4. Находящееся в ящике значение считается текущим значением соответствующей переменной. Это текущее значение может быть выдано из ящика для использования сколько угодно раз, но при этом содержимое ящика не меняется: из него каждый раз выдается копия хранящегося значения с сохранением оригинала в ящике без какого-либо изменения.
  5. К началу выполнения программы содержимое всех запоминающих ящиков считается неопределенным; в частности, их нельзя считать и пустыми, поскольку эти ящики могли использоваться при выполнении предыдущих программ, после чего в ящиках могло что-то остаться.

Еще один оператор действия, хотя его можно лишь условно назвать таковым: он не выполняет никакого действия, это — пустой оператор (в Паскале он обознается знаком «;»). В Паскале оператором действия является также оператор процедуры. Последний из простейших операторов действия — оператор останова, который прерывает работу программы (в Паскале это оператор halt).

Ввод и вывод данных

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

Пример ввода данных с клавиатуры

read(a,b,c);

readln(a,b,c);

Вывод данных на экран производится с помощью стандартной процедуры write( ) или ее разновидности writeln( ).

Список вывода может содержать константы, переменные, выражения, формат вывода. Выражения в списке вывода разделяются запятыми.

Пример вывода данных на экран

write(a,b,c);

writeln(a,b,c);

Окончание ln в имени процедуры означает, что курсор автоматически будет переведен в начало следующей строки экрана.

Программирование

Исходники Pascal (127)

Справочник

Справочник по паскалю: директивы, функции, процедуры, операторы и модули по алфавиту

Урок 13. Процедуры и функции в Pascal. Часть 2

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

Структура программы.

Программы на языке Паскаль состоят из заголовка программы, раздела описаний и тела программы. Раздел описаний может включать следующие подразделы: меток, констант, типов, переменных, процедур и функций. Последовательность подразделов в структуре программы произвольная, но естественно, что если вводится переменная нового типа, заданного в Туре, то подраздел Туре предшествует подразделу Var. Принцип нашего языка программирования «то, что используется, должно быть описано» сохраняется и для раздела описаний.

Структура процедуры и функции

Структура процедуры.

До этого момента времени мы использовали из раздела описаний только описание переменных и типов. На этом занятии мы начнем изучать процедуры. Структура процедуры повторяет структуру программы. Отличия выделены «полужирным» шрифтом.

Напишу простую программу с процедурой, складывающей два числа.

Итак, что вы видите? Точнее, что вам не понятно в данной программе? Я думаю, что вы не можете понять, почему перед z стоит var, а перед x, y — нет. Но всему свое время.

Обратимся к примеру, приведенному на рисунке выше. Слева приведен фрагмент текста основной программы, справа — процедура. Как только в теле программы объявляется имя процедуры с параметрами, выполнение «главного» тела прекращается, и управление вычислительными процессами передается процедуре. После выполнения процедуры осуществляется возврат на оператор основной программы, следующий за вызовом процедуры.

Немножко теории:
В любой программе все переменные делятся на два типа: локальные и глобальные. В нашей программы переменные а, b, с — глобальные, а х, у, z — локальные. Глобальные переменные — это переменные из раздела описаний основной части программы, а локальные — из раздела описаний процедур и функций. Локальные переменные существуют только в течение времени работы процедуры, определяются (создаются) при её вызове и исчезают после завершении работы процедуры.

В программе определены переменные a, b, c. В процедуре x, y, z — её параметры, и они являются переменными процедуры. Причем между х, у и z существует большая разница.

Поясню ее очередным рисунком.

Параметры.

При описании процедуры указывается список формальных параметров. Каждый параметр является локальным по отношению к описываемой процедуре, к нему можно обращаться только в пределах данной процедуры (в нашем примере х, у, z — формальные параметры). Фактические параметры — это параметры, которые передаются процедуре при обращении к ней (а, b, с — фактические параметры). Число и тип формальных и фактических параметров должны совпадать с точностью до их следования.

Параметры-значения.

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

Параметры-переменные.

Другими словами, передача параметров по ссылке. Это те формальные параметры, перед которыми стоит идентификатор var. Передается адрес фактического параметра (обязательно переменной), после этого формальный
параметр становится его синонимом. Любые операции с формальным параметром выполняются непосредственно над фактическим параметром.

Структура функции

Функция выглядит почти так же, как и процедура. Почти единственное отличие в том, что заголовок функции начинается с ключевого слова Function и кончается типом возвращаемого данной функцией значения.

Кроме того, в теле функции обязательно должен быть хотя бы один оператор присваивания, где в левой части стоит имя функции или переменная result, а в правой — ее значение.

Небольшое послесловие:

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

Определение процедур и функций в Pascal

Использование подпрограмм является главной особенностью структурного программирования. По сути, подпрограмма представляет собой составной оператор, объединяющий ряд простых операторов. При этом этот «составной оператор» оснащается именем и внешне оформляется как программа. В подпрограмме бывают свои константы, переменные и другие атрибуты полноценной программы. Локальные переменные никак не связаны с одноименными глобальными переменными (относящимися к основной программе).

Зачем нужны подпрограммы? Их использование удобно, когда в программе несколько раз решается одна и та же подзадача, но для разных наборов данных. Кроме того, использование подпрограмм естественно для человека, которому проще воспринимать логически связанные объекты, чем множество разнородных данных.

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

В большинстве языков структурного программирования подпрограммы существуют только в виде функций. В Паскале же их два типа: процедуры и функции. Их заголовки выглядят соответственно так:

procedure имя (параметры);

function имя (параметры): тип результата;

Между функциями и процедурами есть существенное отличие. Значение, полученное в результате выполнения кода функции, жестко соотносится с ее именем путем присвоения этому имени конкретного значения. Тип, который может принять вычисляемое значение, указывается в заголовке функции (тип результата). И в теле основной программы функция вызывается только в том случае, если ее имя фигурирует в каком-либо выражении. В то время как процедура вызывается отдельно.

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

Когда процедура или функция вызываются, то в скобках вместо формальных параметров, указываются фактические параметры (аргументы). Это могут быть либо конкретные значения, либо переменные из основной программы.

Тело подпрограммы, как и любого составного оператора на языке Паскаль, ограничивается скобками begin и end.

Краткое введение в современный Object Pascal для программистов

1. Введение: Для чего это нужно?

В мире существует множество книг о Паскале, однако, многие из них говорят об «устаревшем» Паскале, без классов, модулей, generic-ов (дженериков) и многих других современных методов и приёмов программирования.

С целью заполнения этой бреши и было написано это краткое введение о том, что часто называется современным объектным Паскалем. Чаще его называют просто «Паскаль» или «Наш Паскаль». Впрочем, представляя язык, важно подчеркнуть, что это современный, объектно-ориентированный язык, который был существенно усовершенствован по сравнению со старым (Turbo) Pascal, который когда-то давно изучали в школах и институтах. Сегодня его вполне можно сравнивать с такими известными языками программирования, как C++, Java или C#.

Паскаль имеет все современные особенности, которые можно ожидать — классы, модульную структуру, интерфейсы, generic-и…​

Паскаль компилируется в быстрый машинный код.

Паскаль является типобезопасным языком, что в некоторых случаях существенно упрощает отладку.

В основном Паскаль — высокоуровневый язызк, однако он имеет возможность использовать низкоуровневые подходы если это необходимо.

Он так же имеет превосходный кроссплатформенный портативный компилятор с открытым исходным кодом: Free Pascal Compiler (http://freepascal.org/). Для него существует несколько IDE (включающих в себя редактор, отладчик, библиотеки компонентов, дизайнер форм), одна из наиболее известных называется Lazarus (http://lazarus.freepascal.org/). Автора данной книги является создателем Castle Game Engine (https://castle-engine.io/) — который является мощным портативным двух- и трёхмерным игровым движком, использующим этот язык, для создания игр под многие платформы: Windows, Linux, MacOSX, Android, iOS, web плагины.

Данное краткое введение в первую очередь ориентировано на программистов, которые уже имеют некоторый опыт в других языках программирования. Здесь не будет раскрываться значение некоторых универсальных концепций, таких как «что такое класс», лишь будет показано как они реализуются в современном Паскале.


Прим.перев. Здесь и далее мы будем использовать оригинальные английские понятия такие как unit, constructor, override, reference-counting в случаях, если они являются ключевыми словами языка либо не имеют общепринятых переводов на русский язык. Также часто предпочитается использовать оригинальное английское слово его транслитерации, как в случае с понятием «generic» выше.

2. Основы

2.1. Программа «Hello world!»

По доброй традиции знакомство с языком начинают с самой базовой и простой программы «Hello world». На Паскале она выглядит следующим образом:

Это — полноценная программа, которую можно скомпилировать и запустить.

Это можно сделать с помощью командной строки FPC, просто создав новый файл myprogram.lpr с кодом программы внутри и выполнив команду fpc myprogram.lpr .

Если используется Lazarus, то необходимо создать новый проект (в строке меню: ProjectNew ProjectSimple Program). Сохраните его как myprogram и скопируйте в него этот исходный код. Компиляция выполняется используя пункт RunCompile в меню.

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

Остальная часть этой книги рассказывает о самом объектном Паскале, поэтому не ожидайте чего-либо большего, чем консольных приложений. Если хочется взглянуть на что-либо более «крутое», можно просто создать новый GUI проект в Lazarus (ProjectNew ProjectApplication). Вуаля! — рабочее кроссплатформенное GUI приложение, с нативным видом, использующее удобные визуальные библиотеки. Lazarus и Free Pascal Compiler имеют множество готовых компонент для сетей, GUI, баз данных, чтения и записи различных форматов файлов (XML, json, изображения…​), управления потоками и всем, что только может понадобиться программисту. Ярким тому примером является Castle Game Engine, о котором упоминалось ранее :)

2.2. Функции, процедуры, простейшие типы

Чтобы задать возвращаемое значение функции, необходимо присвоить какое-либо значение «волшебной» переменной Result в процессе выполнения функции. Её можно свободно читать и устанавливать новое значение так же просто как и любую локальную переменную.

Можно рассматривать имя функции ( MyFunction в примере выше) как переменную, которую можно использовать как самую обычную переменную. Но лично я бы не советовал так делать, поскольку это выглядит не очень «прозрачно», особенно в случае, если это значение используется с правой стороны выражения. Лучше всегда использовать Result , в случае, если необходимо использовать или устанавливать возвращаемое значение функции.

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

Функция Exit служит для завершения выполнения процедуры или функции до того, как она достигнет завершающего end; . Если Exit вызвать без параметров, она вернёт последнее значение, присвоенное Result . Так же можно использовать конструкцию Exit(X) , чтобы установить результат функции и завершить её исполнение немедленно — это эквивалентно конструкции return X в С-подобных языках.

Обратите внимание, что результат функции может быть «проигнорирован» (отброшен). Любую функцию можно вызвать как обычную процедуру. Делать так имеет смысл если функция выполняет некоторые побочные операции (например, изменяет глобальные переменные), а не просто вычисляет некоторый результат. Например:

2.3. Условные операторы (if)

Конструкции if .. then или if .. then .. else запускают определённый код, когда выполняется указанное условие. В отличии от C-подобных языков, в Паскале нет строгого требования ставить условие в скобки.

Оператор else всегда относится только к последнему условию if . Поэтому можно вполне рассчитывать на однозначность выполнения такого кода:

Впрочем, заключение вложенного if внутри блока begin …​ end; является лучшим вариантом, чем предыдущий пример, поскольку он более читабельный, даже если нарушены отступы или большой объём кода и комментариев затрудняет понимание. Таким образом, всегда очевидно к какому if относится данный else — относительно A или относительно B — и, соответственно, куда меньше шансов допустить ошибку при написании кода или при его правках.

2.4. Логические операторы, операторы отношений и побитовые (поразрядные) операторы

Логические операторы представлены в Паскале операторами and , or , not , xor . Их значение в большинстве случаев очевидно для людей, знакомых с компьютерной грамотой. Разве что, за исключением оператора xor , который в русской литературе обычно называется «исключающее или». Эти операторы принимают булевские аргументы (boolean), и возвращаемое значение имеет тот же тип boolean. Они также могут работать как побитовые операторы, в случае, если оба аргумента целого типа (integer, byte или подобные), в этом случае они также возвращают значение идентичного целого типа.

Операторы отношения (сравнения) — представлены следующими комбинациями символов: = , <> , > , , , >= , значение которых вполне очевидно. Следует отметить, что в отличии от синтаксиса С-подобных языков, в Паскале оператор сравнения выглядит как один знак «равно» A = B (в отличии от С, где используется код A == B ). Специальным оператором присваивания в Паскале является := .

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

Следующий пример вызовет ошибку компиляции:

Ошибка связана с тем, что компилятор в первую очередь пытается выполнить побитовый оператор and в середине выражения. В результате получается (0 and B) — побитная операция, возвращающая целочисленную величину. Далее компилятор выполняет оператор «равно» и получает булевскую величину A = (0 and B) . И в конце концов появляется ошибка type mismatch, в результате попытки сравнения булевской величины A = (0 and B) с целочисленной величиной 0 .

Правильно записывать это условие в следующем виде:

Паскаль использует «короткую оценку (short-circuit evaluation)» — мощную оптимизацию, позволяющую не вычислять выражение целиком, если какая-либо его часть полностью определяет результат. Рассмотрим пример:

Значение функции MyFunction(X) всегда рассчитывается первым.

И если MyFunction(X) вернёт значение false , это означает, что мы уже знаем результат всего выражения — какое бы ни было второе значение, при выполнении false and что-нибудь мы всегда получим false . Таким образом MyOtherFunction(Y) вообще не будет выполняться.

Идентичная ситуация и с выражением or . В данном случае, если мы наперёд знаем, что результат будет true потому что первый аргумент имеет значение true , второй аргумент не влияет на результат и не будет рассчитываться.

Это особенно полезно если нужно записать выражение типа:

В данном случае не возникнет ошибки даже в случае если A имеет значение nil . Ключевое слово nil это указатель, который в численном представлении указывает на «нулевой» адрес. Во многих языках программирования он называется нулевым указателем (null pointer).

2.5. Проверка одного выражения на множественные значения (оператор case)

Если в зависимости от разных значений определённого выражения должны быть выполнены разные действия, тогда может оказаться удобной конструкция case .. of .. end .

Условие else опционально (и соответствует default в C-подобных языках). В случае, если текущее значение анализируемого выражения не совпадает ни с одним из описанных случаев и нет условия else , то программа просто пропустит всю конструкцию case и будет выполняться далее.

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

2.6. Перечисляемый и порядковый типы, наборы и массивы постоянной длины

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

Общепринято, что префикс перечисляемого типа состоит из двух букв сокращения имени типа, следовательно ak = сокращение для «Animal Kind». Это полезное соглашение, так как имена перечисляемых типов находятся в глобальном пространстве переменных unit-а. Таким образом, с помощью префикса ak автоматически уменьшаются шансы на случайный конфликт с другими идентификаторами.

Конфликты в именах не приводят к неработоспособности программы. Вполне допустимо в различных unit-ах определять одинаковые идентификаторы. Однако, желательно избегать подобных конфликтов везде, где это возможно, чтобы код был прост для понимания и анализа.
Можно избежать попадания имён перечисляемых типов в глобальное пространство с помощью директивы компилятора <$scopedenums on>. В таком варианте будет необходимо обращаться к ним через имя типа следующим образом: TAnimalKind.akDuck . В результате отпадает необходимость в префиксе ak , и можно просто оставить исходные названия Duck, Cat, Dog . Такое исполнение подобно тому, как работают перечисляемые списки в C#.

Прозрачность перечисляемого типа означает, что он не совместим напрямую с целочисленными величинами. Тем не менее, если такая совместимость необходима, можно использовать Ord(MyAnimalKind) , чтобы вручную привести список к целочисленному типу. Обратная операция будет выглядеть как приведение типа TAnimalKind(MyInteger) и превратит целое число в соответствующий перечисляемый тип. В последнем случае необходимо также быть уверенным, что MyInteger является частью диапазона от 0 до Ord(High(TAnimalKind))) .

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

Они также могут использоваться для создания наборов (они же set-ы, они же внутренние битовые поля):

2.7. Циклы (for, while, repeat, for .. in)

Может показаться, что различие между циклами while и repeat лишь «косметические» с единственным отличием, что условие записано «с точностью до наоборот»: в случае while .. do выполнение продолжается, пока условие истинно, а при repeat .. until — выполнение прекращается, когда условие истинно. Впрочем, есть ещё одно важное отличие: в случае repeat , условие проверяется не в начале, а в конце цикла. Поэтому содержимое цикла repeat всегда выполняется как минимум один раз.

Конструкция for I := .. to .. do …​ похожа на C-подобный цикл for . Тем не менее, она более ограничена, поскольку невозможно указать произвольное действие/условие чтобы контролировать итерации цикла. В Паскале for используется строго для итерации через последовательные числа (или другие порядковые типы). Единственной уступкой является возможность использования downto вместо to , чтобы производить счёт в обратном порядке.

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

Следует также обратить внимание, что переменная, которая использовалась для цикла (в примере выше — I ) становится неопределённой после окончания цикла кроме случая досрочного выхода из цикла с помощью команд Break или Exit . Цикл for I in .. do .. такой же как конструкция foreach в многих других языках и хорошо понимает организацию всех встроенных типов:

Он может перебирать все значения массива (см. пример выше).

Он может перебирать все возможные значения перечисляемого типа:

Он может перебирать все элементы набора:

И так же работает на всех пользовательских типах, включая generic-и, например, TObjectList или TFPGObjectList .

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

2.8. Вывод информации и логов

Для простого вывода строки в Паскале используется процедура Write или WriteLn . Во втором случае в конце автоматически добавляется символ переноса строки.

Это «волшебная» процедура в Паскале, Она принимает переменное число аргументов, которые могут иметь практически любой тип. Они все будут автоматически сконвертированы в строчный тип при выводе. Кроме того, можно добавить специальный синтаксис для указания каким образом отформатировать число.

Чтобы явным образом добавить перенос строки можно использовать константу LineEnding (из библиотеки FPC RTL). (Castle Game Engine имеет также более краткий вариант NL ). В отличии от HTML и других подобных синтаксисов разметок в Паскале обратная косая ( \ ) не позволяет вставлять специальные символы в строке, например:

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

Стоит отметить, что функции Write / WriteLn будут работать только в консольных приложениях. Для этого необходимо указывать <$apptype CONSOLE>(но не <$apptype GUI>) в главном файле программы. На некоторых ОС консоль явно или скрыто присутствует всегда (Unix) и эта директива не используется. А в некоторых системах попытка выполнения Write / WriteLn из GUI приложения приведёт к ошибке (например, в Windows).

В Castle Game Engine не советуется использовать WriteLn , поскольку для этого есть специальная функция WriteLnLog или WriteLnWarning для вывода логов и отладочной информации. Их результат всегда будет направлен в полезном направлении: для Unix-подобных систем это будет стандартный вывод в консоль. Для Windows GUI приложений это будет лог-файл. В Android вывод будет направлен в Android logging facility (инструмент логов Андроида), который можно просматривать с помощью команды adb logcat . Использовать WriteLn есть смысл лишь в ограниченном наборе случаев, например, для консольных приложений (исполняемых из командной строки) в которых можно быть точно уверенным, что стандартный вывод определён. Например, так можно делать в конвертере или генераторе трёхмерных моделей, который предназначен для запуска из командной строки.

2.9. Преобразование данных в строчный тип

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

Некоторые конкретные типы можно преобразовать в строку используя специальные функции, такие как IntToStr и FloatToStr . В дальнейшем суммировать (concatenation) строки в Паскале можно просто используя знак сложения. Таким образом можно создавать составные строки: ‘Моё целое число ‘ + IntToStr(MyInt) + ‘, а значение числа пи составляет ‘ + FloatToStr(Pi) .

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

Второе преимущество: они почти всегда имеют обратную функцию. Чтобы преобразовать строку (например, введённую пользователем) в целое или дробное число можно использовать StrToInt , StrToFloat и подобные (например, StrToIntDef ).

Недостаток: длинная сумма множества XxxToStr и строк выглядит некрасиво.

Функция Format используется в виде Format(‘%d %f %s’, [MyInt, MyFloat, MyString]) . Она подобна функции sprintf в C-подобных языках. Она вставляет аргументы в соответствующие placeholder-ы согласно заданному образцу. Эти placeholder-ы могут использовать специальный синтаксис, влияющий на форматирование, например %.4f это дробный формат с 4 знаками после запятой.

Преимущество: отделение строки от аргументов выглядит чисто и красиво. Легко изменить текст строки, не изменяя аргументов, например, если необходимо выполнить перевод.

Второе преимущество: не используются «волшебные» свойства компилятора. Можно использовать идентичный синтаксис для передачи произвольного количества аргументов произвольного типа в пользовательских процедурах (для этого определите принимаемый параметр как array of const ). Затем можно передать эти аргументы функции Format , или разобрать на список параметров и делать с ним всё, что угодно.

Недостаток: компилятор не проверяет, соответствует ли строка-образец аргументам. Используя неверный тип placeholder-а приведёт к ошибке EConvertError , впрочем, гораздо более понятной, чем segmentation fault (наиболее часто SIGSEGV).


В Паскале также существует функция WriteStr(TargetString, …​) во многом подобна базовой функции Write(…​) , с одним отличием — результат сохраняется в TargetString .

Преимущество: эта функция имеет все возможности функции Write , в том числе и специальный «волшебный» синтаксис для форматирования, как например Pi:1:4 .

Недостаток: такой специальный синтаксис для форматирования является «волшебным», т.е. он написан специально для конкретной процедуры. Часто это приводит к проблемам, например, невозможно создать свою функцию MyStringFormatter(…​) которая бы принимала такой синтаксис, как Pi:1:4 . Именно по этому, а также из-за того, что эта функция долгое время не была доступна в основных компиляторах, такая конструкция не очень популярна.

3. Модули (Unit-ы)

Unit-ы позволяют группировать общие функции и объекты (любые элементы языка, которые могут быть объявлены), для использования другими unit-ами и программами. Они эквивалентны модулям и пакетам в других языках. Они имеют секцию interface , где объявляются доступные для других unit-ов и программ переменные, функции и т.п., и секцию implementation , где описано, как они работают. Unit MyUnit можно сохранить под именем myunit.pas (название должно состоять из строчных букв с расширением .pas ).

Файл основной программы чаще всего сохраняется в виде файлов типа myprogram.lpr ( lpr = Lazarus program file; в Delphi используются .dpr ). Следует отметить, что возможны и другие расширения, например, некоторые проекты используют расширение .pas для основного файла программы. Для unit-ов изредка используются расширение .pp . Лично же я предпочитаю использовать стандартные .pas для unit-ов и .lpr для FPC/Lazarus программ.

Программа может подключать unit с помощью ключевого слова uses :

Unit может также содержать секции initialization и finalization . В них размещается код, который выполняется при запуске и завершении выполнения программы, соответственно.

3.1. Перекрёстные ссылки между unit-ами

Не только основная программа, но и unit-ы также могут ссылаться на другие unit-ы. Другой unit может войти в секцию interface или только в implementation. Первый вариант позволяет создавать новые определения (процедуры, типы…​), используя или наследуя информацию из другого unit-а. Во втором варианте возможности более ограничены — если использовать unit в секции implementation, то применить его идентификаторы возможно лишь в рамках implementation данного unit-а.

Запрещено применять кольцевую взаимозависимость (cyclic reference) в разделе interface. Т.е. два unit-а не могут использовать друг друга в разделе interface. Причина такого ограничения заключается в том, что для того, чтобы «понять» секцию interface unit-а, компилятор анализирует и «понимает» все unit-ы, перечисленные в uses в секции interface. В Паскале это правило придерживается строго, что позволяет достичь высокой скорости компиляции и полностью автоматическое определение компилятором что именно необходимо перекомпилировать. В Паскале нет необходимости создания сложных Makefile для выполнения простой задачи компиляции, а также нет нужды перекомпилировать всё лишь для того, чтобы удостовериться, что все зависимости правильно обновились.

Вполне возможно создавать кольцевые зависимости между unit-ами когда один из них «используется» только в implementation. Поэтому нормально для A использовать B в interface, и затем unit B использует A в implementation.

3.2. Определение идентификаторов с указанием имени unit-а

Различные unit-ы могут определять одинаковые идентификаторы. Чтобы поддерживать код простым для чтения и правки, обычно следует избегать таких совпадений, но не всегда это возможно. В таких случаях, последний unit в списке uses «перетягивает одеяло на себя», т.е. идентификаторы определённые в нём скрывают одноимённые идентификаторы введённые другими unit-ами ранее.

Однако, возможно недвусмысленно определить unit предоставляющий идентификатор, с помощью конструкции MyUnit.MyIdentifier . Это стандартное решение ситуации, когда используемый идентификатор из MyUnit скрыт идентификатором из другого unit-а. Для достижения этой же цели можно просто перестроить порядок unit-ов в списке uses, однако это повлияет на все идентификаторы, что не всегда желательно.

В случае unit-ов следует также помнить, что они могут иметь два списка uses : один — в секции interface , другой — в implementation . Основное правило в этом случае звучит как: «позднейшие unit-ы скрывают все что было до этого» и применяется последовательно, что в свою очередь означает, что unit-ы использованные в секции implementation могут скрывать идентификаторы из unit-ов использованных в секции interface. Кроме того, не стоит забывать, что в процессе обработки секции interface данного unit-а компилятором, влияют лишь unit-ы использованные в секции interface. Это может сбить с толку в ситуациях, когда два на вид одинаковых объявления обрабатываются компилятором по-разному:

Unit Graphics (из набора библиотек Lazarus LCL) определяет тип TColor . Но компилятор указывает на ошибку в этом unit-е, указывая на то, что заявленная в секции Interface процедура ShowColor не описана. Проблема в том, что unit GoogleMapsEngine также определяет тип TColor , который используется только в секции implementation , следовательно он перекрывает определение TColor в секции implementation . Т.е. компилятор видит это буквально как:

В данном случае решение тривиальное: необходимо просто изменить implementation , чтобы явно использовать TColor из unit-а Graphics . Это также можно исправить, переместив GoogleMapsEngine в секцию interface до unit-а Graphics . Впрочем, это может привести к другим последствиям внутри unit-а UnitUsingColors , так как коснётся всех его определений.

3.3. Передача идентификаторов одного unit-а через другой

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

В некоторых случаях это делается из-за необходимости сохранить обратную совместимость с предыдущими версиями unit-а. А иногда таким образом удобно «скрыть» какой-либо unit для внутреннего пользования.

Это может быть осуществлено с помощью повторного объявления идентификатора в новом unit-е.

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

Более оптимальным решением является создание тривиальной «функции-обёртки», которая под видом простого вызова функции из внешнего unit-а, просто передаёт ему параметры и возвращает принимаемые значения обратно.

Чтобы проделать то же с глобальными параметрами иногда используются глобальные (на уровне unit-а) свойства, см. Свойства.

4. Классы

4.1. Основы

В Паскале для объектно-ориентированного программирования чаще всего используются классы (classes). На базовом уровне класс просто является «контейнером», который может вмещать в себя:

поля (field) (иными словами «переменная внутри класса»),

методы (method) (иными словами «процедура или функция внутри класса»),

свойства (property) (удобный синтаксис для конструкции подобной полю, однако в действительности являющейся парой методов, используемых для чтения (getter) и записи (setter) чего-либо; детальнее см. [Properties]).

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

4.2. Наследование (Inheritance), проверка (is), и приведение типов (as)

Паскаль поддерживает наследование и виртуальные методы объектно-ориентированного программирования.

По умолчанию методы не являются виртуальными и для объявления их виртуальными необходимо использовать ключевое слово virtual . Перекрытие или замещение виртуального метода осуществляется с помощью ключевого слова override , иначе компилятор выдаст ошибку. Чтобы скрыть метод без перекрытия используется ключевое слово reintroduce , впрочем, без особых на то причин, так делать не стоит.

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

Вместо приведения типа в виде X as TMyClass , можно использовать приведение типа без проверки с помощью выражения TMyClass(X) . Такой код будет работать чуть-чуть быстрее, но может привести к неопределённому поведению в случае если X не является наследником TMyClass . По этому конструкцию TMyClass(X) лучше не применять кроме тех случаев, когда абсолютно очевидно, что X действительно является наследником TMyClass , например, если до этого тип класса был проверен с помощью оператора is :

4.3. Свойства

Свойства (Properties) являются «синтаксическим сахаром» (прим. перев. syntax sugar — жаргон, означающий синтаксические возможности, применение которых не влияет на поведение программы, но делает использование языка более удобным для программиста) который можно использовать с целью:

Сделать что-то внешнее похожее на поле (может быть прочитано и установлено), но реализовано вызовом функций считывания значения (getter) и установки значения (setter). Самое стандартное применение такого подхода — автоматическое выполннение дополнительных действий каждый раз, когда некоторое значение изменяется.

Сделать что-то внешне похожее на поле, но доступное только для чтения — нечто, похожее на константу или функцию без параметров.

Стоит обратить внимание, что вместо того, чтобы указать метод для чтения или записи, можно напрямую указать читаемое/записываемое поле (которое обычно является private и весьма часто имеет название идентичное property с дополнительным префиксом f (от field — поле)) чтобы непосредственно получать или устанавливать значение. В примере выше, свойство Color использует setter-метод SetColor . Однако, для получения значения свойство Color напрямую ссылается на private поле FColor . Прямая ссылка на конкретное поле, очевидно, быстрее, чем написание дополнительных методов getter или setter — как с точки зрения разработки, так и с точки зрения скорости исполнения программы.

При объявлении свойства указывается:

Может ли оно быть прочитано, и как (с помощью прямого чтения поля, или с использованием метода getter ).

Может ли оно быть установлено, и как (с помощью прямой записи поля, или вызовом метода setter ).

Компилятор следит за тем, чтобы типы и параметры соответствующих полей и методов совпадали с типом свойства с которым они работают. Например, чтобы прочитать свойство Integer следует или предоставить поле Integer , или беспараметрический метод (функцию), который возвращает Integer .

С технической точки зрения, методы «getter» и «setter» — обычные методы и они могут делать абсолютно что угодно (включая массу дополнительных функций). Всё же правилом хорошего тона является создание таких свойств, которые ведут себя более-менее подобно обычному полю:

Функция getter не должна иметь невидимых побочных эффектов (например, она не должна читать некоторый ввод из файла / с клавиатуры). Её значение должно быть детерминистическим (без рандомизации или псевдо-рандомизации :)) — чтение свойства должно всегда иметь смысл и возвращать одинаковый результат, если между операциями чтения ничего не изменилось.

Следует отметить, что вполне нормально если выполнение getter имеет некие невидимые последствия, например, сохранение в кеше результатов какого-либо вычисления для ускорения выполнения кода при следующем вызове. По факту, это одна из очень полезных возможностей функции «getter».

Функция setter должна всегда устанавливать значение таким образом, чтобы getter вернул его же обратно. Не стоит автоматически отбрасывать неверные значения «setter», а в случае, когда это необходимо, следует вызвать exception. Также не желательно конвертировать или масштабировать запрашиваемое значение. Главная идея заключается в том, чтобы после установки My > можно было с уверенностью сказать, что My >.

Свойства, доступные только для чтения часто используют для создания неких полей доступных из внешнего кода только для чтения. Снова таки, хорошая практика — делать их поведение похожим на константу, по крайней мере для данного экземпляра класса в его текущем состоянии. Значение такого свойства не должно меняться неожиданно. Если необходимо возвращать что-то случайное, лучше сделать функцию, а не свойство.

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

Технически, возможно создать свойства, которые только устанавливают значение, но не читают его. Впрочем, хороших примеров такой реализации лично мне ещё не встречалось :)

Свойства так же могут быть определены вне класса, на уровне unit-а. Они служат аналогичной цели: они внешне выглядят как глобальные переменные, но доступ к ним вызывает соответствующие функции getter и setter.

4.3.1. Сериализация (Serialization) свойств

Свойства, имеющие уровень Published являются основой для сериализации (serialization) (также называемой передачей компонент в потоке (streaming components)) в Паскале. Слово «Serialization» происходит от слова «Series» — «ряд», т.е. сериализация подаёт свойства объекта в виде некоторого линейного ряда данных, такого как например, запись в памяти или в файле.

Собственно, именно сериализация и происходит в момент, когда Lazarus читает или записывает состояние компонент из/в файл xxx.lfm . В Delphi эквивалентный файл имеет расширение .dfm . Этот механизм можно использовать и в своих целях, с помощью процедур таких как ReadComponentFromTextStream из unit-а LResources . Также можно использовать другие алгоритмы сериализации, например unit FpJsonRtti представляет возможность сериализации в популярном формате JSON.

В Castle Game Engine можно использовать unit CastleComponentSerialize (созданный на основе FpJsonRtti ) для сериализации иерархии наших собственных компонент, таких как user-interface и transformation.

При каждом свойстве можно указать дополнительные параметры, которые будут полезны при использовании любого алгоритма сериализации:

Можно указать значение свойства «по умолчанию» с помощью ключевого слова default . Обратите внимание, что всё равно следует инициализировать свойство с помощью значения по умолчанию — это не происходит автоматически. Значение default это лишь указание алгоритму сериализации: «когда закончится выполнение constructor-а, то данное свойство имеет это значение».

Сохранять ли это свойство вообще — с помощью ключевого слова stored .

4.4. Исключения

В паскале можно вызывать и использовать исключения. Их можно «ловить» с помощью конструкции try …​ except …​ end , также можно применять секцию «выполнить в конце» try …​ finally …​ end .

Обратите внимание, что раздел finally будет выполнен даже в случае, если выполнение будет прекращено командой Exit (из функции, процедуры или метода), операторами Break или Continue (внутри тела цикла).

4.5. Уровни видимости

Как и в большинстве других объектно-ориентированных языков, в Паскале имеются визуальные спецификаторы для ограничения «видимости» полей / методов / свойств.

Основные уровни видимости являются следующими:

предоставлен доступ из любого участка кода, включая код в других unit-ах.

доступен только в этом классе.

доступен только в этом классе и всех его наследниках.

Краткое описание private и protected , данное выше, не полностью верно. Код в текущем unit-е может преодолевать эти границы, и получать доступ к секции private и protected . Иногда это полезная особенность, позволяющая реализовывать тесно связанные классы. В остальных же случаях следует использовать strict private или strict protected для организации полной недоступности данных методов, полей или свойств извне класса. Детальнее этот вопрос рассматривается в разделе Различие private и strict private.

По умолчанию, если видимость не указана явно, то она соответствует public . исключение составляют классы, которые объявляются при включённой директиве <$M+>, либо наследники классов, которые были скомпилированы при <$M+>, что включает в себя всех потомков TPersistent , включая потомков TComponent , который сам является потомком TPersistent . Для таких классов по умолчанию видимость принимается published , которая подобна public , однако позволяет работать с ними с помощью потоковой (stream) системы.

Однако, не каждому типу поля или свойства позволено быть в секции published — не каждый тип может быть конвертирован в поток (stream), и лишь классы, состоящие из простых полей, могут передаваться потоком. Если нет необходимости создавать потоки, но нужно просто сделать что-то доступное для всех пользователей, то следует использовать public .

4.6. Предок по умолчанию

Если явно не объявить родительский класс, то по умолчанию каждый class наследует TObject .

Pascal для начинающих. Краткий справочник.

Pascal для начинающих

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

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

Файл в формате PDF

Эта информация хранится в формате PDF. Для её чтения может понадобиться специальная программа. Например, бесплатная программа Adobe Reader.

Илон Маск рекомендует:  Получить количество строк в TextArea
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL