© 2006 Рудюк С.А.
Компания НеРуСофт
Память для переменных, объявленных в разделе var выделяется во время компиляции. Такая память называется статической. Однако, часто не известно сколько памяти нужно программе и выделяется память во время выполнения. Такая память называется динамической.
Адреса переменных можно хранить в указателях. Указатели – это ячейки памяти специального типа. Они объявляются таким образом:
var
<название
переменной-указателя>:^<тип>;
^ - это указатель.
Пример объявления указателя:
var
my_int: ^integer;
my_real: ^real;
По умолчанию, все указатели имеют значение nil, что означает, что переменная никуда не указывает. Одинаковые указатели можно присваивать друг-другу. Для того, чтоб получить значение указателя необходимо воспользоваться операцией разыменовывания указателя (для этого знак указателя ставится после переменной).
Например:
write(my_int^); - печатает значение переменной-указателя my_int.
Для того, чтоб получить адрес переменной необходимо перед переменной написать знак @. Например:
@my_int – определение адреса переменной my_int.
Для того, чтоб работать с динамическими переменными, необходимо под неё выделить память. Для этого предназначена процедура New( ). После завершения работы с переменной необходимо освободить указатель, вызвав команду Dispose( ).
Если в процессе работы есть необходимость изменять тип указателя, тогда следует воспользоваться нетипизированным указателям. Он объявляется таким образом:
var
my_struct: pointer;
Для работы с такими указателями предусмотрено ряд функций [7]:
procedure GetMem(var P: Pointer; Size: Integer);
// Выделяет для
указателя P память размером
Size.
procedure FreeMem(var P: Pointer [;
Size:
Integer]);
// Освобождает
память, заданную указателем.
function SizeOf(X): Integer;
// Возвращает
размер памяти, выделенной для указателя
В FreePascal определены две конструкции для обработки исключительных ситуаций [4]:
try
<операторы>;
finally
<операторы, которые должны выполняться в любом
случае>
end;
Если возникает ошибка среди операторов между try и finally, тогда программа переходит к выполнению операторов, находящихся между finally…end;
try
<операторы>;
except
<операторы, которые выполняются при возникновении
ошибки>
end;
Если возникает ошибка среди операторов между try и except, тогда программа переходит к выполнению операторов, находящихся между except…end;
В конструкции try…except предусмотрен оператор с помощью которого можно получить точный текст и код ошибки – это оператор on..do. Такой оператор ставится только между except…end. Пример его использования:
try
s:=m/0;
except
on E: Exception do
begin
WriteLn('Произошла ошибка:');
WriteLn(E.Message);
end
else
Raise;
end;
Оператор Raise передаёт управлению стандартному обработчику исключительных ситуаций.
Пример: Выведем результаты деления 10 на все целые цифры от -10 до 10.
Листинг программы (на компакте в папке try):
program consple_laz;
// Программа выводит результаты деления 10 всех цифр, начиная от -10 до 10
{$mode objfpc}{$H+}
{$AppType CONSOLE}
Uses SysUtils;
var i: integer;
begin
for i:=-10 to 10 do
begin
try
writeln(format('10/%d=%f',[i, 10/i])); // Выводим результат от деления
except
on E: Exception do // Если возникла ошибка, тогда выводим ошибку
begin
writeln(format('10/%d=%s',[i, E. Message]));
end;
end;
end;
readln;
end.
Прокомпилируйте программу с помощью комбинации Ctrl+F9 и запустите из exe-файл программы (для того, чтоб не выскакивали окна среды разработки при возникновении ошибки). Получите результат:
10/-10=-1,00
10/-9=-1,11
10/-8=-1,25
10/-7=-1,43
10/-6=-1,67
10/-5=-2,00
10/-4=-2,50
10/-3=-3,33
10/-2=-5,00
10/-1=-10,00
10/0=Division by zero
10/1=10,00
10/2=5,00
10/3=3,33
10/4=2,50
10/5=2,00
10/6=1,67
10/7=1,43
10/8=1,25
10/9=1,11
10/10=1,00
Обычно, большая часть программы находится за пределами основного файла проекта, в отдельных файлах, которые называются модулями (юнитами).
Модули – это программные единицы, служащие для размещения фрагментов программ.[7]
Структура модулей:
unit Test;
interface
// Глобальные объявления и переменные
implementation
// Локальные объявления и переменные
initialization
// Код, выполняемый при запуске программы
finalization
// Код завершения работы программы
end;
Раздел инициализации initialization является не обязательным. Он необходим для выполнения кода при запуске программы.
FreePascal является объектно-ориентированным языком программирования. В основе объектной модели Паскаля лежат понятия класса и объекта. [7]
Классами называются специальные типы, которые содержат поля, методы и свойства.
Объект – это конкретный экземпляр класса.
В объектно-ориентированных языках есть 3 основных понятии: инкапсуляция, наследование и полиморфизм.
Инкапсуляцией называется объединение в классе данных и подпрограмм для их обработки. Инкапсуляция позволяет создавать класс, как нечто целостное, имеющее определённую функциональность.[7]
Наследование – это когда любой класс может быть порождён другим классом.[7] Порождённый класс автоматически наследует все поля, методы, свойства и события.
Полиморфизм позволяет использовать одинаковые имена для методов, входящих в различные классы.[7]
Для объявления класса используется конструкция:
type
<название класса> = class(<название класса-родителя>)
<методы и переменные класса>
private
<локальные объявления, доступные только в пределах модуля>
protected
<защищенные объявления, доступные только в классах-потомках>
public
<глобальные объявления, доступные из других модулей>
published
<свойства и методы, видимые в инспекторе объектов (для публикации)>
end;
В каждом из разделов могут находиться описания полей, свойств, методов и событий. Ниже, мы опишем, что их более подробно.
Обратите внимание, что в классе предусмотрены различные области видимости объектов.
private – методны, свойства, сопытия и поля видны только в области текущего класса;
protected – то же, но в текущем объекте и объектах-потомках.
public - то же, но видно везде.
published – видно везде, а так же свойство или метод показывается в инспекторе объектов среды разработки.
Полями называются инкапсулированные в классе данные. Поля класса подобны полям записи, но в отличие от них могут быть любого типа, в том числе и классами.[7]
type
TMyClass = class
FirstName: String;
SecondName: String;
Obj_Control: TObject;
end;
Для того, чтоб обратиться к классу необходимо записать названия класса и через точку название поля. Например:
var M: TMyClass;
begin
M.FirstName:='Иванов';
M.SecondName:='Иван';
M.Obj_Control:=nil;
end;
Свойства аналогично выглядят, как и поля, но в отличие от полей, свойства могут управлять доступ к полям. Для получения информации в свойстве используется зарезервированное слово Get, а для установки значения свойства – Set.
Например:
type
TMyClass = class
Constructor Create;
Destructor Destroy;
FFullName: String;
function GetFullName: String; Virtual; abstract;
property FullName: String read GetFullName write FFullName;
end;
В этом примере при вызове значения (read) свойства FullName выполняется вызов функции GetFullName, а запись (write) производися в функцию FFullName.
Если необходимо производить запись через процедуру, тогда процедура должна быть с параметром Value:<тип свойства>. Например, для случая выше можно было написать процедуру: procedure SetFullName(Value: String).
Методами называются инкапсулированные в классе процедуры и функции.[7]
Например:
type
TMyClass = class
FirstName: String;
SecondName: String;
Obj_Control: TObject;
function GetFillName: String;
end;
Обращение к методам идём по аналогии со свойствами, например:
Name:=M.GetFullName;
Различают статические, динамические и виртуальные методы.
По умолчанию, считается, что метод статический. Например:
type
TMyClass = class
function GetFillName: String;
end;
TMyUniverClass = class(TMyClass)
function GetFillName: String;
end;
var MyC: TMyClass;
MyUniver: TMyUniverClass;
begin
WriteLn(MyC.GetFillName);
WriteLn(MyUniver.GetFillName);
end;
В данном случае, компилятор просто заменит метод GetFillName в классе TMyUniverClass новой версией метода.
Динанамические и виртуальные методы замещаются во время выполнения. Различия между этими методами не вилико и отличается только реализацией. Виртуальные методы более эффективны с точки зрения скорости, а динамические – с точки зрения занимаемой памяти.
Для того, чтоб метод стал виртуальным, необходимо указать словао virtual после метода, а для того, чтоб метод стал динамическим, не обходимо указати слово dynamic.
type
TMyClass = class
function GetFillName: String; Virtual; // Виртуальный метод
function Dinamo: String; Dynamic; // Динамический метод
end;
Абстрактными называются динамические или виртуальные методы, которые не совершают никаких действий. Такие методы нужны для создания иерархии методов.
type
TMyClass = class
function GetFillName: String; Virtual; abstract;
end;
В любом объекте есть две процедуры: Create и Destroy. Одна называется Конструктор, другая – деструктор. Так, как классы (объекты) – динамические структуры, то Конструктор создаёт объект, а Деструктор его разрушает.
type
TMyClass = class
Constructor Create;
Destructor Destroy;
function GetFillName: String; Virtual; abstract;
end;
Для того, чтоб вызвать в любом методе одноименный метод-предок, необходимо выполнить команду inherited. Если метод-предок отличается по параметрам, тогда необходимо после inherited повторить процедуру-предка с параметрами.
Для разрушения объектов существует так же метод Free. Данный метод перед выполнением команды Destructor вначале проверяет был ли в самом деле создан объект. Поэтому, более корректно вызывать метод Free.
Событие – это свойство процедурного типа, и его значением является указатель на некоторый метод. Позже, при рассмотрении графической среды разработки Вы столкнётесь с этим понятием много раз. Каждый раз, когда Вы щелчком на событии в среде разработки создаёте новое событие, компилятор связывает созданное событие с полем для события в компоненте. [7]
© 2006 Рудюк С.А.,
Компания НеРуСофт
Специально для Delphi Plus
Пожалуйста, оцените статью