Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Paskal.docx
Скачиваний:
2
Добавлен:
16.09.2019
Размер:
73.34 Кб
Скачать

Загрузка и выгрузка модулей

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

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

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

Объектно-ориентированное программирование

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

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

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

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

Конструктор и деструктор задаются как обычные процедуры, но вместо идентификатора procedure задаются ключевые слова constructor и destructor. Соответственно, в отличие от С++-подобных языков они имеют имя, отличное от имени класса, деструкторов может быть несколько и они могут иметь параметры (на практике эта возможность используется редко, обычно класс имеет единственный деструктор Destroy, переопределяющий виртуальный деструктор класса-родителя).

Поддерживаются единичное наследование, полиморфизм классов, механизм виртуальных методов (слово virtual после заголовка метода класса). Существуют и динамические методы (в TP описываются путём добавления целого числа после слова virtual и используются преимущественно для обработки сообщений; в Delphi и FreePascal для этих целей используется слово message, а для создания обычных динамических методов — слово dynamic), отличающиеся меньшим использованием памяти и меньшей скоростью вызова за счёт отсутствия дублирования динамических методов предков в VMT потомка (однако FreePascal не делает различий между виртуальными и динамическими методами).

В Delphi, FPC реализована перегрузка операций, абстрактные методы, директивы private, protected, public, published (по умолчанию члены класса являются public):

type

TbasicO = object

procedure writeByte (b:byte); virtual; abstract;

end;

TtextO =object (TbasicO) {наследует TbasicO, реализует остальные операции вывода на основе writeByte}

procedure writeS (s: string);

{..}

end;

TfileO = object (TbasicO) {класс файлового вывода - реализует операцию вывода как вывод байта в файл}

constructor init (n: string);

procedure writeByte (b: byte); virtual;

destructor closefile;

private

f: file of byte;

end;

basicO = ^TbasicO;

textO = ^TtextO;

fileO = ^TfileO;

constructor TfileO.init (n: string);

begin

assign (f, n);

rewrite (f)

end;

destructor TfileO.closefile;

begin

close (f)

end;

procedure TfileO.writeByte (b: byte);

begin

write (f, b)

end;

procedure TtextO.writeS (s: string);

var i: integer;

begin

for i:=1 to length(s) do

writeByte (ord(s[i]))

end;

{..}

var f: fileO;

begin

new (f, init('tstobj.txt')); {выделяет пямять под объект и вызывает конструктор}

textO(f)^.writeS ('text string');

dispose (f, closefile) {вызывает деструктор и освобождает память объекта}

end.

В диалекте Delphi классы могут также конструироваться с помощью слова class (причём взаимное наследование с object-классами не допускается) и введены интерфейсы (interface) — все методы абстрактные и не могут содержать полей данных.

Все классы (созданные с помощью class) являются наследниками TObject, все интерфейсы происходят от IUnknown. Классы, созданные с помощью class, могут реализовывать несколько интерфейсов.

В Delphi интерфейсы были введены для поддержки технологии COM фирмы Microsoft.

Классы (Class) в отличие от обычных классов (Object) не нуждаются в явном выделении/освобождении памяти, память под них динамически выделяется конструктором с именем Create, вызываемым с именем класса, и освобождается при вызове деструктора с именем Destroy (могут иметь другие имена). Переменная такого класса в отличие от класса object хранит адрес экземпляра класса в памяти, значение nil используется для указания пустой ссылки, поэтому для освобождения объекта в TObject определен специальный метод free, проверяющий ссылку на nil и вызывающий виртуальный деструктор Destroy. Код с использованием таких классов будет выглядеть следующим образом:

q1 := t1.create(9); { конструируем объект(t1 - имя класса) }

writeln (q1.InstanceSize); { вывод размера экземпляра класса }

q1.Free; { уничтожение объекта }

q1 := nil; { чтобы не происходило повторного вызова деструктора при вызове free }

В модификации ObjectPascal/Delphi/FreePascal в описании классов появляются свойства (property), которые совмещают удобство работы с переменными (роль которых в ООП играют поля) и вызовы методов, которые всегда уведомляют объект об изменении его состояния:

type

TMyObj=class(TObject)

FProp:integer;

procedure SetProp(AValue:integer);

property MyProp:integer read FProp write SetProp;

end;

procedure TMyObj.SetProp(AValue:integer);

begin

FProp:=AValue;

Writeln('Somebody has changed MyProp!');

end;

var MyObj:TMyObj;

begin

MyObj:=TMyObj.Create;

MyObj.FProp:=5;

MyObj.MyProp:=MyObj.MyProp+6;

end.

В первом случае (использование MyObj.FProp) поле объекта было изменено непосредственно, в итоге, методы объекта не будут подозревать, что это поле было ранее изменено; в более сложном случае они могут полагаться на то, что поле неизменно, либо же полю может быть присвоено значение, недопустимое для данного объекта. Во втором случае значение присваивается непосредственно свойству объекта, которое ссылается на вызов метода, корректно обрабатывающего изменение данного поля. Этот подход удобен, если объект связан с визуальным элементом: непосредственное изменение поля, отвечающего, например, за ширину элемента, никак не отразится на самом визуальном элементе, а объект будет «дезинформирован» относительно реальных размеров элемента. Корректным подходом без использования свойств является разработка методов на получение и установку любого значения поля, но работа с такими методами будет менее удобна, например, вместо последней строки надо было бы написать

MyObj.SetProp(MyObj.GetProp+6);

,

причём метод MyObj.GetProp следовало бы написать для унификации доступа. Большой интерес представляют индексные свойства, которые ведут себя практически так же, как и массивы, заменяя обращение к элементу массива вызовом соответствующего метода. Тем не менее, свойства не являются «панацеей»: при компиляции обращение к свойствам непосредственно транслируются в вызов методов или прямую работу с полями, поэтому настоящими переменными свойства не являются, в частности, их невозможно передавать в виде var-параметров.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]