Материал: Основы разработки программных средств в среде Delphi. Романов А.В

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

3.3.7. Файлы

Различают файлы трех видов: текстовые файлы, типизированные файлы и нетипизированные файлы.

Текстовые файлы состоят из последовательностей символов, разбитых на строки. В Object Pascal предопределен тип TextFile, соответствующий текстовому файлу. Таким образом, объявление файловой переменной может иметь вид:

var <имя файловой переменной>: TextFile;

Работа с текстовыми файлами осуществляется процедурами и функциями файлового ввода/вывода. Основные процедуры чтения – Read, ReadLn, Write и WriteLn.

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

var <имя файловой переменной>: file of <тип данных>;

var F: file of real; // пример

Процедуры чтения и записи Read и Write для типизиро­ванных файлов не отличаются от соответствующих процедур для текстовых файлов. Не определены процедуры Readln и Writeln, но есть процедура Seek, позволяющая перемещаться по файлу не только последовательно, как в текстовых файлах, а сразу переходить к требуемому элементу. Имеется также функция FilePos, возвращающая текущую позицию в файле.

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

var <имя файловой переменной>: file;

Открытие нетипизированных файлов осуществляется процедурами Reset и Rewrite, синтаксис которых несколько отличен от аналогичных процедур для других видов файлов тем, что в этих процедурах указывается размер одной записи в байтах. Для записи и чтения данных в нетипизированных файлах имеются процедуры BlockRead и BlockWrite, которые читают или записывают указанное в них число записей.

3.3.8. Указательные типы

Указатель является величиной, указывающей на некоторый адрес в памяти, где хранятся какие-то данные. Указатели бывают типизированные, указывающие на данные определенного типа, и нетипизированные (типа pointer), которые могут указывать на данные произвольного типа. Используются указатели обычно для работы с объектами в динамически распределяемой области памяти, особенно при работе с записями.

Объявление указателя имеет вид:

type <имя типа указателя> = ^<тип данных>;

F1 = ^real; // типизированный указатель

F2 = pointer; // нетипизированный указатель

Предопределена операция @, возвращающая адрес своего операнда: переменной, функции, процедуры, метода. Иначе говоря, операция @ создает указатель на свой операнд. При этом если X – переменная, то @X возвращает адрес X, причем при директиве компилятора {$T–} (включена по умолчанию) тип результата pointer. В случае функции или процедуры с именем F – @F возвращает точку входа, причем тип результата всегда pointer. Также существует предопределенная константа nil, которая обычно присваивается указателям, которые в данный момент ни на что не указывают.

Чтобы получить доступ к данным, на которые указывает типизированный указатель, надо применить операцию его разыменования. Она записывается с помощью символа ^, помещаемого после указателя. Например, для того, чтобы по адресу объявленного типизированного указателя на тип real F1 находилось какое-либо число, необходим оператор вида F1^:=0.18;. Операция разыменовывания не применима к типу pointer. Для разыменовывания подобного указателя сначала необходимо привести его к другому типу.

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

3.3.9. Вариантные типы

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

Переменные типа variant занимают 16 битов и содержат код типа и значение переменной или указатель на это значение. Узнать действительный тип значения переменной variant можно с помощью функции VarType, возвращающей значение типа TVarData, содержащее код типа. Переменные типа variant могут использоваться в выражениях как операнды любых операций, кроме ^, is и in, совместно с другими величинами типов variant, integer, real, string, boolean. Компилятор в этих случаях автоматически осуществляет приведение типов величин в выражении.

3.3.10. Объекты, классы и интерфейсы

Класс – это тип данных, определяемый пользователем. То, что в Delphi имеется множество предопределенных классов, не противоречит этому определению – ведь разработчики Delphi тоже пользователи Object Pascal. Понятие объекта (object) использовалось при зарождении объектно-ориентирован­ного программирования при переходе от Pascal к Object Pascal. В настоящее время тип object практически эквивалентен классу. В научно-технической литературе можно встретить иную интерпретацию термина "объект" – как конкретный экземпляр или инициализированную переменную класса.

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

Type

<имя класса> = Class (<имя класса - родителя>)

public {доступно всем}

<поля, методы, свойства, события>

published {видны в Инспекторе Объекта и изменяемы}

<поля, свойства>

protected {доступ только потомкам}

<поля, методы, свойства, события>

private {доступ только в модуле}

<поля, методы, свойства, события>

end;

Имя класса может быть любым допустимым идентификатором, однако идентификаторы большинства классов принято начинать с символа "T". Имя класса-родителя может не указываться. Тогда предполагается, что данный класс является непосредственным наследником TObject – наиболее общего из предопределенных классов. Таким образом, эквивалентны следующие объявления:

type TMyClass = class

...

end;

type TMyClass = class(TObject)

...

end;

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

Раздел public (открытый) предназначен для объявлений, которые доступны для внешнего использования. Это открытый интерфейс класса. Раздел published (публикуемый) содержит открытые свойства, которые появляются в процессе проектирования на странице свойств Инспектора Объектов и которые, следовательно, пользователь может устанавливать в процессе проектирования. Раздел private (закрытый) содержит объявления полей, процедур и функций, используемых только внутри данного класса. Раздел protected (защищенный) содержит объявления, доступные только для потомков объявляемого класса. Как и в случае закрытых элементов, можно скрыть детали реализации защищенных элементов от конечного пользователя. Однако, в отличие от закрытых, защищенные элементы остаются доступны для программистов, которые захотят производить от этого класса производные объекты, причем не требуется, чтобы производные объекты объявлялись в этом же модуле.

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

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

Объявление интерфейса имеет вид:

type

<имя интерфейса>=interface(<имя интерфейса-родителя>)

['GUID']

<список элементов>

end;

Имена интерфейсов принято начинать с символа "I". Имя интерфейса-родителя может отсутствовать. В этом случае интерфейс наследует непосредственно классу IUnknown – базовому классу всех интерфейсов. Интерфейс, подобно классу, наследует от своих родителей все методы, но не наследует их реализацию. Может также отсутствовать указание GUID – глобального уникального идентификатора, который задается строкой шестнадцатеричных символов (от 0 до F) вида ['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'].

Объявление интерфейса в основном аналогично объявлению класса и имеет следующие ограничения:

  • список элементов может включать только методы и свойства (с соответствующими методами для чтения и записи), но не может включать поля;

  • все методы интерфейса открытые (public), т.е. при объявлении метода необходима инструкция stdcall;

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

3.4. Операторы языка Object Pascal

3.4.1. Оператор присваивания

Оператор присваивания записывается в виде: <переменная> := <выражение>; где <переменная> – это переменная или типизированная константа любого типа, включая разыменованный указатель, объект, структуру и т.д., а <выражение> – любое допустимое выражение, совместимое по типу с переменной в левой части оператора. Оператор вычисляет значение выражения, записанного как правый операнд операции присваивания :=, и присваивает полученное значение переменной в левой части оператора. Например, оператор I:=3 присваивает переменной I значение 3, а оператор I:=I+1 увеличивает значение переменной I на 1.

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

3.4.2. Оператор безусловного перехода

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

L1: <оператор, на который передается управление>

Сам оператор goto имеет форму:

goto <метка>;

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

3.4.3. Оператор if

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

В общем виде оператор условного перехода имеет вид:

if <условие> then <оператор1> else <оператор2>;

Если условие возвращает true, то выполняется первый из указанных операторов, в противном случае выполняется второй оператор. Заметим, что в конце первого оператора перед ключевым словом else точка с запятой не ставится. Ветвь с else может отсутствовать. Тогда при невыполнении условия управление передается следующему за конструкцией if оператору. Например, в результате выполнения операторов

C := A;

if B > A then C := B;

переменная C станет равна максимальному из чисел A и B, поскольку оператор C:=B будет выполнен только при B>A.

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

if <условие1> then if <условие2> then <оператор1>

else <оператор2>;

else будет отнесено компилятором ко второй конструкции if, т.е. <оператор2> будет выполняться в случае, если первое условие истинно, а второе ложно. Иначе говоря, вся конструкция будет прочитана как

if <условие1> then begin

if <условие2> then <оператор1> else <оператор2>

end;

Если же необходимо отнести else к первому if, то это надо реализовывать как составной оператор, т.е. записать в явном виде с помощью операторных скобок begin...end.

if <условие1> then begin

if <условие2> then <оператор1>

end

else <оператор2>

Источник: https://studfile.net/preview/16568022/