Это метод программирования, опирающийся на структурную организацию программы

Вид материалаДокументы
Операция "равно" (=)
Операция "не равно" ()
Операция "меньше или равно" (
Объединение множеств (+).
Разностью множеств (-).
Неформатный вывод в файл
Форматный вывод в текстовый файл
Подобный материал:
1   2   3   4   5

Внимание! Количество элементов множества не должно превышать 256, соответственно номера значений базового типа, получаемые функцией ord(MyElement) для элемента MyElement нашего множества, должны находиться в диапазоне 0..255.


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

Объем памяти = (Max div 8) -(Min div 8) + 1,

где Max и Min — верхняя и нижняя границы базового типа.

При работе с множествами допускается использование операций отношения "=", "<>", ">=", "<=", объединения ”+”, пересечения “*”, разности “-“ множеств и операции in. Результатом выражений с применением этих операций является значение True или False.

Операция "равно" (=).

A=B

Два множества A и B считаются равными, если они состоят из одних и тех же элементов. Порядок следования элементов в сравниваемых множествах значения не имеет.

Операция "не равно" (<>).

A< >B

Два множества A и B считаются не равными, если они отличаются по мощности или по значению хотя бы одного элемента.

Операция "больше или равно" (>=).

A>=B

Используется для определения принадлежности множеств. Результат операции A>=B равен True, если все элементы множества B содержатся в множестве A. В противном случае результат равен False.

Операция "меньше или равно" (<=).

A<=B

Используется аналогично предыдущей операции, но результат операции A<=B равен True, если все элементы множества A содержатся в множестве B. В противном случае результат равен False.

Операция in.

X in A

Используется для проверки принадлежности какого-либо значения выражения x указанному множеству A. Обычно применяется в условных операторах. Не путать с оператором <=, который используется для сравнения двух множеств.

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

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

if (a=1) or (a=2) or (a=3) or (a=4) or (a=5) or (a=6) then ... можно заменить более коротким выражением if a in [1,2,3,4,5,6] then ... . Иногда операцию in пытаются записать с отрицанием: X not in M. Такая форма ошибочна, так как две операции следуют подряд; правильная инструкция имеет вид not (X in M).

Объединение множеств (+).

Объединениям двух множеств является третье множество, содержащее элементы обоих множеств.

Пересечением множеств (*).

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

Разностью множеств (-).

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

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

2.10.5. Файловые типы. Операторы write, writeln, assignFile, read, readln,reset, rewrite, closeFile.

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

Файлы являются структурными типами с особыми правилами работы с ними. В данном параграфе описываются операторы для работы с файлами.

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

type tF=file of t1

var f:tF;

либо var f:file of t1;

тут t1 – базовый тип файлового типа, то есть тип ячеек, из которых состоит файл.

Для работы с файлами надо сначала определить файловую переменную (например, F1), имеющую тип, соответствующий типу файла, с которым будет осуществляться работа. Для этого используется процедура: assign(F1, Name: string), где строковое выражение Name содержит полное имя файла, удовлетворяющее требованию операционной системы. Пример:

var F1: file of integer;



assign File(F1,'data1.x');

Файловая переменная (в нашем случае F1) выполняет роль указателя на файл, а оператор assign “перещелкивает” его с одного файла на другой. Причем до первого assign значение этого указателя неопределено.

В процессе работы файловой переменной можно переприсваивать имена файлов.

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

Для работы с текстовыми файлами существует предопределенный тип файлов Text:

var F: text;



assign File(F,'data.txt');

Существуют также нетипизированные файлы. Соответствующие файловые переменные описываются как var F:file.

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


Неформатный вывод в файл:
  • write(F1,a); write(F1,b,c,...,d) — вывод в файл “подряд” всех значений. Эквивалентно write(F1,a,b,c,…,d).
  • writeln(F1,a); writeln(F1,b,c,...,d) — имеет смысл только для текстовых файлов. После вывода всех перечисленных в операторе параметров в конец добавляется перевод на новую строку. В данном примере — после вывода a и после вывода d.

Другой пример:

writeln(F1a); writeln(F1b);...; writeln(F1c); — после вывода в файл любого параметра туда добавляется перевод на новую строку.

Оператор writeln; без параметров используется для перехода на новую строку.


Форматный вывод в текстовый файл:
  • write(F1x:n1) — вывод значения целой, вещественной, булевской или строковой величины x (либо x как элемент множества) в правую сторону поля длинной n1. Если x - вещественная величина , она выводится в научной нотации.
  • write(F1x:n1:n2) — вывод вещественной величины x в нотации с фиксированной десятичной точкой, n2 (лежащее от 0 до 24) — число знаков после точки. Например, при x=1.234567e-987 оператор write(F1x:12:3) дает -1.234e-0987, а write(F1x:12:2) дает -1.23e-0987.

Оператор read(F,a) читает из файла, назначенного файловой переменной F, значение с текущего места позиционирования считывающей головки и передвигает головку на один элемент файла по направлению к концу файла. Установка в конец файла должна производиться программным путем с проверкой значения предопределенной переменной Eof на значение true, достигаемое в случае, если вместо следующего элемента в файле стоит маркер конца файла.

Консоль (монитор и клавиатура компьютера) является файлом чтения/записи по умолчанию, когда файловая переменная не указывается. Запись эквивалентна выводу в текстовом режиме на экран, чтение – вводу с клавиатуры. В Delphi такой формы операторов wride, writeln, read, reddln пользуются только в специальном режиме имитации консоли.

Оператор readln; обычно используют для приостановки работы программы до нажатия пользователем клавиши , readln(a) — для ввода с клавиатуры значения переменной a.

Оператор rewrite(F) создает новый файл с именем, назначенным в данный момент файловой переменной F. Если файл с таким именем уже существует, он без предупреждения затирается.

Установка в начало файла производится оператором reset(F).

После окончания работы с файлом (перед новым вызовом assignFile(F,…) или выходом из программы) надо выполнить команду closeFile(F), иначе операционная система будет поддерживать файл открытым. Максимальное число одновременно открытых файлов зависит от версии и установок операционной системы. Если closeFile(F) вызвать после очередного assignFile , то предыдущий файл останется открытым и закроется операционной системой только после выхода из программы. Закроется же текущий файл, на который была настроена переменная F во время вызова последнего assign с ее участием.

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

В Delphi имеется расширение PASCAL. Вместо операторов assign и close, использовавшихся в ТР, приняты совершенно идентичные им, но имеющие более осмысленные названия assignFile и closeFile. Кроме того, имеются операторы blockRead и blockWrite, позволяющие производить блочные чтения и запись с произвольного места в файле. Надо отметить, что при работе с текстовыми файлами лучше пользоваться этими операторами. Имеются также:
  • булевская функция fileExists (имя файла), возвращающая true, если файл с таким именем существует,
  • процедура flush (файловая переменная) – очищает буфер с немедленной записью в файл,
  • процедура seek(var F;N:longInt) – смещает указатель файла F к компоненту с номером N (нумерация идет от нуля),
  • функция fileSize(varF):longInt – возвращает число компонентов файла ,
  • функция filePoz(varF):longInt – возвращает текущую позицию в файле (то есть для очередных чтения или записи).

Замечание: переход в конец файла – с помощью seek(F,fileSize(F)). Кроме того, имеется много других процедур и функций.


2.11. Указатели. Динамические переменные. Динамическое выделение и высвобождение памяти

В языке PASCAL имеются структурные типы особого рода (pointers), получившие название указателей, либо, что то же самое, ссылок. Они предназначены для динамического выделения памяти под данные. В разделе декларации указатели описываются следующим образом: если имеется некий предопределенный или определенный пользователями тип tAnyType, то тип — указатель на переменную var MyVariable:tAnyType описывается как type tpAnyType=tAnyType, а переменная ссылочного типа может быть описана либо как var pAnyType:tpAnyType, либо сразу как var pAnyType:tAnyType без специального объявления типа tpAnyType.

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

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

Рассмотрим следующий пример:

procedure PtrDemo1;

var p1,p2:Integer;

a,b:Integer;

begin

a:=1;

b:=2;

New(p1); {в "куче"(heap) динамически выделена ячейка — область под

"безымянную" переменную типа Integer, указатель p1 настроен

на эту ячейку}

p1:=a+5; {в эту ячейку записывается значение 6}

p2:=p1; {на эту ячейку теперь указывают и p1, и p2, в ней - число 6}

New(p1); {динамически выделяется еще одна ячейка, p1 переключается на нее,

а p2 остался настроен на прежнюю}

b:=p2-1; {переменной b присваивается значение, содержащееся в первой

ячейке, уменьшенное на 1,то есть 5}

{значение p1не определено, p2= 6}

dispose(p1); {высвобождаем память, выделенную под ячейку2}

dispose(p2); {высвобождаем память, выделенную под ячейку1}

end;

В данном примере видно, что указатель можно использовать не только для динамического выделения памяти, как это происходит с p1 , но и для сохранения программой связи с выделенной ячейкой, для чего используется p2. Если бы мы вовремя не настроили p2 на первую динамически выделенную ячейку памяти, при втором вызове New(p1) мы бы потеряли к ней доступ, указатель p1 "перещелкнулся" бы на вторую динамически выделенную ячейку, и образовывался бы так называемый "мусор" (garbage) в памяти: область, помеченная операционной системой как занятая задачей, но самой задаче уже недоступная.

Следующий тонкий момент при работе с указателями — высвобождение динамически выделенной памяти. К окончанию работы программы вся динамически выделенная память должна быть "возвращена обратно". Это делается с помощью оператора dispose, который "уничтожает" (т.е. высвобождает) ячейку, на которую ссылается указатель. Сам указатель при этом не уничтожается и может быть в дальнейшем использован!

Часто встречающаяся в программах ошибка — использование указателя доступа к данным после того, как ячейка на которую он ссылался, высвобождена. Этот случай аналогичен попытке использования неинициализированных (т.е. "не настроенных" на конкретную ячейку) указателей и часто кончается "зависанием" компьютера, такие указатели часто называют "висящими" ("dangling pointer").

Пример работы с указателями:

program PtrDemo2;

type tpInt=Integer; {тип "ссылочный на Integer"}

var p1,p2:tpInt;

...

begin

...

New(p1); {выделили ячейку1 и настроили на нее p1}

...

New(p2); {выделили ячейку2 и настроили на нее p2}

...

dispose(p2); {высвободили ячейку2, но p2 "жив"}

p2:=p1; {настроили p2 на ячейку1}

New(p1); {выделили ячейку3 и настроили на нее p1}

...

dispose(p1); {высвободили ячейку3}

...

dispose(p2); {высвободили ячейку1}

end.

Следует помнить, что каждому New (вызванному, к примеру, с указателем p1) должен соответствовать свой dispose(вызванный, к примеру, с p2), и чтобы указатели p1 и p2 указывали бы на одну и ту же ячейку. Попытка лишний раз сделать dispose, т.е. повторно высвободить один и тот же участок памяти, обычно сразу заканчивается аварийной остановкой программы. Иногда указатели используются для получения ссылки на переменную, процедуру или функццию. Для этого в Object Pascal имеется функция addr (вместо нее можно использовать символ @ при соответствующей установке опции компилятора).


2.12. Процедуры и функции. Формальные и фактические параметры. Передача параметров по ссылке, по значению и через указатель.

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

program factor1;

procedure factorial(var x:extended; n:integer); {заголовок

процедуры}

var i:integer; {раздел описания переменных}

begin

x:=1; {тело процедуры}

for i:=1 to n do x:=x*i; {тело процедуры}

end;

var x,y,z:extended; {раздел описания переменных программы}

i,k,l:integer; {раздел описания переменных программы}

begin {начало тела программы}

i:=7; k:=2; l:=100;

factorial(x,i);

factorial(y,(k+l)/2-5*i);

{factorial (z+1,l); — так нельзя!}

factorial(z,l); {так можно}

end. {конец тела программы}

Иногда (как в данном случае) гораздо удобнее использовать процедуру-функцию:

program factor2;

function factorial(n:integer):extended; {заголовок функции с

формальным параметром n}

var i:integer; {локальная переменная функции factorial}

x:extended; {локальная переменная функции factorial}

begin

x:=1; {тело функции}

for i:=1 to n do x:=x*i; {тело функции}

factorial:=x;

end;

var x,y,z:extended; {глобальные переменные программы}

i,k,l:integer; {глобальные переменные программы}

{эти x и y совсем не то, что локальные в factorial}

begin

i:=7; k:=2; l:=100;

x:=factorial(i); {вызов1}

y:=factorial((k+l)/2-5*i); {вызов2}

z:=factorial(l); {вызов3}

end.

При описании процедуры (или функции) переменные, описанные в заголовке процедуры — это формальные параметры (в примере fact2 это n для функции factorial). В теле программы при вызове процедуры на соответствующее место надо подставлять фактические (это строка i в вызове1, (k+l)/2-5*i в вызове2, l в вызове3). Если перед формальным параметром стоит зарезервированное слово var — это передача параметра "по ссылке". В этом случае вместо формального параметра подставляется фактическая переменная соответствующего типа, и если в процессе работы процедуры (или функции) должно меняться значение формального параметра, то реально меняется значение этой переменной. После окончания работы процедуры эта переменная сохраняет изменившееся значение. Т.о. через такой параметр можно передавать значения как "внутрь" процедуры, так и "наружу" из нее. В ряде современных языков программирования такой способ передачи параметров описывают как сочетание in ("внутрь") и out ("наружу"). Смысл термина "передача параметра по имени" следующий: при работе процедуры вместо имени формального параметра подставляется имя фактического, и именно с ним проделывается все то, что описано в процедуре.

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

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


2.13. Локальные и глобальные переменные. Побочный эффект функции. Вложенность процедур и функций. Правила видимости.

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


2.14. Пример на правила видимости и передачи параметров

unit factorials;

uses . . . ;

var

k,n,m: integer; {глобальные целые переменные}

p:extended;

ch: char; {глобальная литерная переменная}

function fact1(n:integer): extended;{процедура-функция, передача

входного параметра n по значению}

var i: integer;

begin

if n=0 then n:=1;

result:=1;

for i:=1 to n do result:=result*i;

end;

procedure fact2;{процедура, передача входного параметра через

глобальную переменную n, возврат результата через

глобальную переменную p}

var i: integer;

result:extended;

begin

if n=0 then n:=1;

result:=1;

for i:=1 to n do result:=result*i;

p:=result;

end;

procedure fact3(n:integer; var r:extended);{процедура, передача

входного параметра n по значению,

возврат результата через параметр r по имени}

var i: integer;

result:extended;

begin

if n=0 then n:=1;

result:=1;

for i:=1 to n do result:=result*i;

r:=result;

end;

function fact4(n:integer):extended; {процедура-функция, передача

входного параметра n по значению, побочный

эффект – изменение глобальной переменной m}

var

i: integer;

begin

if n=0 then n:=1;

result:=1;

for i:=1 to n do result:=result*i;

fact4 =result;

m:=m+1;{побочный эффект}

end;

begin {тело основной программы}

k:=…;

m:= 0;n:=…;p=…;

case ch of

'1' : p := fact1( n );

'2' : fact2 ;

'3' : fact3( n , p );

'4' : p := fact4( n );

end;

……

End.


2.15. Рекурсия

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

factorial(1)=1; для n>1: factorial(n)= factorial(n-1)*n.

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


function factorial(n:integer):extended;

begin

result:=1;

if n>=1 then result:=n*factorial(n-1)

end;

У рекурсии есть недостатки: а) при каждом вложенном вызове создается копия локальных переменных процедуры, они храняться в стеке. При большой глубине вложенности стек может переполниться; b) очень часто встречается ситуация бесконечной рекурсии. Так, если бы мы не написали условия n>=1, рекурсные вызовы продолжались бы вплоть до переполнения:

function factsfoo(n:integer):extended;

begin

result:>=n*factorial(n-1)

end;


Основные принципы объектно-ориентированного программирования (ООП) на примере языка Object Pascal (Delphi) со статической версией объектной модели


Рассматриваемая версия объектной модели характерна для языка TurboPASCAL (TP5.5 – TP7.0) и очень близка к объектной модели C++ ( за исключением того, что в C++ поддерживается также множественное наследование и ряд других дополнительных возможностей). В Delphi эта модель поддерживается, но рассматривается как устаревшая. Основной считается модель с динамически создаваемыми объектами, во многом близкая по идеологии к объекной модели языка Java.


2.1. Инкапсуляция. Объект. Поля данных и методы объекта

Инкапсуляцией называется объединение каких-либо относительно независимых элементов в единое целое. В стандартном PASCAL существует тип record — "Запись":

type

tLocation=

record {поля записи}

X,Y:Integer

end;

var Location1,Location2:tLocation;

a:integer;

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

a:=Location1.X

Либо изменить значение поля Y:

Location1.Y:=212

А можно действовать с инкапсулированными в запись полями как с единым целым:

Location2:=Location1

при этом полю X записи Location1 будет присвоено значение X записи Location2, и, аналогично, полю Y в Location1 — значение Y записи Location2.

Развитием идеи объединения (инкапсуляции) различных полей стали объекты.

Пример:

объект:

точка на экране tDot;

ее данные:

координаты X и Y — целые переменные;

светится или нет на экране active — булевская переменная;

ее методы действия:

"нарисовать": Show;

"скрыть": Hide;

"передвинуть по X и Y на величины dX и dY": Move(dX,dY)

"передвинуть в точку с координатами X и Y": MoveTo(X,Y)

Использование в программе:

var aDot:tDot;

...

aDot.X:=10; {координате X точки Dot присвоить значение 10}

aDot.Y:=20;

aDot.Show; {вызвать метод показа точки Show; говорят: "точка себя рисует"}

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

procedure tDot.Show;

begin

… {рисование точки текущим цветом пера}

active:=true;

end;

procedure tDot.Hide;

begin

… {рисование точки цветом фона}

active:=false;

end;

procedure tDot.Move(dX,dY:Integer);

begin

Hide;

X:=X+dX;

Y:=Y+dY;

Show;

end;


3.2 Задание модуль класса (статическая объектная модель)

Теперь мы можем наметить, как будет выглядеть модуль с нашим классом:

Unit myFigure;

uses …;

interface

type

tDot=

object

X,Y:Integer;

active:Boolean;

procedure Show;

procedure Hide;

procedure MoveBy(dX,dY:Integer); {сдвиг на dX,dY}

procedure MoveTo(NewX,NewY:integer);{рисование в точке NewX,NewY}

end;

tCircle=

object(tDot)

...

end;

implemetation

{——— раздел реализации ———}

procedure tDot.Show;

begin

...

end;

procedure tDot.Hide;

begin

...

end;

procedure tDot.MoveBy(dX,dY:Integer);

begin

...

end;

procedure tDot.moveTo(X,_,Y_:integer);

begin



end;

begin

{раздел инициации. Всегда делать пустым!!!}

end.


Модули. Секции декларации, интерфейса и реализации. Области видимости.

На самом деле общая структура модуля при наличии в нем класса несколько сложнее. Обсудим ее более подробно.

Написание собственного модуля (unit) начинается с указания имени модуля. В нашем случае он называется myFigure. Он должен храниться в файле с тем же именем, но с расширением .pas (файл языка PASCAL), т.е. myFigure.pas.

unit myFigure;

{- секция декларации -}

interface

uses ... , m1,…; {наш модуль кроме списка модулей, автоматически созданного Delphi, использует модули m1 и т. Д.}

type

tDot=

object

active:Boolean;

X,Y:integer;

procedure Show;

procedure Hide;

procedure MoveBy(dX,dY:Integer);

procedure MoveTo(NewX_,NewY_:Integer);

procedure Init(X_,Y_,:Integer);{процедура инициализации объекта}

{если в объекте есть поля X и Y, то эти имена нельзя использовать в

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

символ _ после имени, чтобы было понятно, к использованию какого поля

объекта относится передаваемый параметр}

end;

tCircle=

object(tDot)

...

end;

procedure... {описание процедур и функций, видимых в других модулях}

var... {описание глобальных переменных, видимых в других модулях}

{- секция реализации -}

implementation

uses m2,m3; {модули m2 и m3 доступны процедурам и функциям области

реализации}

var ...; {описание глобальных переменных,доступных только в данном модуле}

{-описание реализации методов объектов-}

procedure tDot.Show;

begin

...

end;

procedure tDot.Hide;

begin

...

end;

procedure tDot.Move(dX,dY:Integer);

begin

...

end;

procedure tDot.MoveTo(NewX,NewY:Integer);

begin

...

end;

procedure tDot.Init(X_,Y_:Integer);

begin

X:=X_;

Y:=Y_;

tDot.Hide;

end;

procedure tCircle...;

begin

...

end;

...

begin {секция инициализации — обычно пустая}

end.

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


Классы, экземпляры класса, наследование, иерархия.

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

Var dDot:tDot

переменная dDot – это объект.

tDot — тип-прародитель (класс-прародитель),
  • tCircle=

object(tDot) {тип-наследник (класс-наследник)};

...

end;
  • tRectangle=

object(tDot) {другой наследник};

...

end;

Тут tCircle и tRectangle — прямые потомки tDot (т.е. он их прямой прародитель) и т.п.

Далее можно определить другие классы-наследники:
  • tTriangle=

object(tDot)

...

end;
  • tFilledTriangle=

object(tTriangle)

...

end;
  • tFilledCircle=

object(tCircle)

...

end;
  • tRedCirlce=

object(tCirlce)

...

end;
  • tGreenCirlce=

object(tCirlce)

...

end;
  • tFilledRectangle=

object(tRectangle)

...

end;