Соглашения по передаче данных

Существуют четыре варианта передачи данных в подпрограммах:

· Register - базовый режим, который задаётся по умолчанию и характеризуется тем, что может быть использовано до трех регистров процессора для передачи данных. Регистры – внутренняя память процессора, которая необходима непосредственно для проведения вычислений;

· Pascal, отличающийся от предыдущего режима, в основном тем, что регистры процессора для передачи параметров не используются;

· Cdecl, являющийся режимом, позволяющим использовать DLL, написанные на C++ или на других языках;

· Stdcall, являющийся режимом, позволяющим обращаться к подпрограммам Windows.

ДИРЕКТИВА FORWARD

При объявлении подпрограмм существует правило, нельзя использовать подпрограмму, если она не объявлена и не определена. Если подпрограмма Б вызывает А, а А вызывает Б (циклический вызов), то в этом случае, чтобы не нарушать правило, указанное выше, первую из подпрограмм объявляют с директивой Forward и после этого определяют сначала вторую, а потом первую подпрограммы. Например,

Procedure First(var x : Integer); Forward;

Procedure Second(var x,y : Single);

First(x); . . . . .

end;

Procedure First(Var x : Integer);

Second(z1,z2); . . . . .

end;

ДИРЕКТИВА EXTERNAL

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

Procedure First; external ‘MyDll.dll’;

Во втором случае имя DLL опускается.

ДИРЕКТИВА ASSEMBLER

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

Function Max(x,y:integer):Integer; Assembler;

ASM {Вместо begin}

Mov eax, x

Cmp eax, y {сравнить}

Jge @1 {перейти}

Mov eax, y

@1: end;

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

ПЕРЕГРУЖЕННЫЕ ПОДПРОГРАММЫ

Часто возникает потребность выполнять одни и те же действия над разными типами данных. Например, как удобно работать с функцией Abs(X) – возвращение модуля числа. Если аргумент X - число целое, то результат возвращается, как целое число, если аргумент – число вещественное, то и результат будет числом вещественным. Для создания подпрограмм, которые в зависимости от типа аргумента возвращают разный тип результата, используется механизм перегрузки подпрограмм. Синтаксически перегруженные подпрограммы объявляются с директивой overloadи, кроме того, подпрограмма определяется отдельно для каждого типа аргумента. Например,

Procedure ShowResult(I:integer); overload;

Begin

ShowMessage(IntToStr(I));

End;

Procedure ShowResult(R:real); overload;

Begin

ShowMessage(FloatToStr(R));

End;

Procedure ShowResult(S:string); overload;

Begin

ShowMessage(S);

End;

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

ShowResult(2); ShowResult(5.7);

ShowResult(‘Перегруженная процедура’)

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

ПРИМЕР 13

Пусть заданы два числа k1 и k2. С помощью генератора случайных чисел, распределённых равномерно, создаются два множества такие, что первое содержит число k1, а второе – k2. Если k2 намного больше k1, то можно предположить, что в большинстве случаев сумма элементов второго множества больше суммы элементов первого множества. Проверить сформулированное утверждение на трёх парах множеств. Количество элементов во множестве равно k. Диапазон чисел от 0 до L=100.

В данном случае требуется сгенерировать 6 множеств. Обозначим их S01, S02, S11, S12, S21, S22. Для записи элементов этих множеств воспользуемся компонентом TPageControl, который находится на странице Win32 палитры компонентов.

Форма с вариантом решения представлена на рис. 33.

соглашения по передаче данных - student2.ru

Рис. 33 Форма с вариантом расчета примера 13.

Компонент TpageControl используется для реализации многостраничных диалоговых панелей. Каждая страница представляет собой объект типа TTabSheet (лист с этикеткой). Название страницы задаётся свойством Caption. Текущая страница доступна через свойство ActivePage. Страницы нумеруются, начиная с нуля. При переключении страниц возникает событие OnChange. На каждой странице могут быть расположены любые компоненты: TEdit, TMemo, TImage и т.д. Заголовки страниц могут отображаться или в одну строку со скроллингом или в несколько строк. В последнем случае свойству MultiLine необходимо присвоить значение true.

Для нашего примера были выбраны три страницы (с помощью правой клавиши мыши выбирается NewPage). На каждой странице расположено по два компонента типа TMemo: соответственно от Memo1 до Memo6.

Для ввода чисел k, k1, k2 использовался компонент TSpinEdit (страница Samples). Ввод с помощью этого элемента ограничивается только целыми числами. Их можно вводить или непосредственно или с помощью встроенных стрелок, последовательно уменьшая или увеличивая число. Само число содержится в свойстве Value.

В данном случае для решения примера понадобятся дополнительные подпрограммы. Создадим одну подпрограмму для генерации (пример 12) множеств (назовём её CreateMn), другую (SumMn) – для нахождения суммы элементов множества. Расположим эти подпрограммы в секции Implementation модуля как необходимые для решения внутренних задач.

Выберем тип Procedure для первой подпрограммы: она должна возвращать элементы множества. Вторая подпрограмма должна возвращать значение суммы (одно число), поэтому её оформим в виде Function. Программа приводится ниже.

unit prim13;

Interface

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs,

StdCtrls, Buttons, ComCtrls, Spin, ExtCtrls;

Type

TForm1 = class(TForm)

Panel1: TPanel;

Panel2: TPanel;

SpinEdit1: TSpinEdit;

SpinEdit2: TSpinEdit;

Label2: TLabel;

Label3: TLabel;

SpinEdit3: TSpinEdit;

Label4: TLabel;

BitBtn2:TBitBtn;

Button2:TButton;

PageControl1: TPageControl;

TabSheet1: TTabSheet;

TabSheet2: TTabSheet;

TabSheet3: TTabSheet;

Memo1: TMemo;

Memo2: TMemo;

Memo3: TMemo;

Memo4: TMemo;

Memo5: TMemo;

Memo6: TMemo;

procedure PageControl1Change(Sender: TObject);

procedure Button2Click(Sender: TObject);

end;

constL=100;

type mn=set of 0..L;

var Form1: TForm1;

s:array [0..2,1..2] of mn;

ss:mn = [];

k,k1,k2:byte;

Implementation

{$R *.DFM}

procedure CreateMn(n:byte);

var i,j,z:byte;

begin

if n=1 then ss:=[k1] else ss:=[k2];

for j:=0 to 2 do

repeat

s[j,n]:=[];

for i:=1 to k do

while true do begin

z:=random(L+1);

if z in s[j,n] then continue;

include(s[j,n],z);

break;

end;

until s[j,n]>=ss;

end;

function SumMn(const np,n:byte):word;

var i:byte;

begin

result:=0;

for i:=1 to L do

if i in s[np,n] then result:=result+i;

end;

procedure TForm1.Button2Click(Sender: TObject);

var k12:integer;

const str='не выполняется условие ';

begin

randomize;

k12:=SpinEdit1.Value;

if (k12>L) or (k12<0) then begin

ShowMessage(str+'0<=k1<L');

SpinEdit1.SetFocus;

exit;

end;

k1:=k12;

k12:=SpinEdit2.Value;

if (k12>L) or (k12<0) then begin

ShowMessage(str+'0<=k2<L');

SpinEdit2.SetFocus;

exit;

end;

k2:=k12;

k12:=SpinEdit3.Value;

if k12<=0 then begin

ShowMessage(str+'k>0');

SpinEdit3.SetFocus;

exit;

end;

k:=k12;

CreateMn(1);

CreateMn(2);

end;

procedure TForm1.PageControl1Change(Sender: TObject);

var i:byte;

str1,str2:string;

CurrentTab:TTabSheet;

CurrentMemo1:TMemo;

CurrentMemo2:TMemo;

begin

str1:='';

str2:='';

CurrentTab:=PageControl1.ActivePage;

CurrentMemo1:=nil;

CurrentMemo2:=nil;

case CurrentTab.PageIndex of

0:begin

CurrentMemo1:=Memo1;

CurrentMemo2:=Memo2;

end;

1:begin

CurrentMemo1:=Memo3;

CurrentMemo2:=Memo4;

end;

2:begin

CurrentMemo1:=Memo5;

CurrentMemo2:=Memo6;

end;

end;

if (CurrentMemo1 <> nil) and

(CurrentMemo2 <> nil) then begin

CurrentMemo1.Lines.Clear;

CurrentMemo2.Lines.Clear;

for i:=0 to L do begin

if i in s[CurrentTab.PageIndex,1] then

str1:=str1+inttostr(i)+' ';

if i in s[CurrentTab.PageIndex,2] then

str2:=str2+inttostr(i)+' ';

if i mod 20 = 0 then begin

if length(trim(str1))>0 then begin

CurrentMemo1.Lines.Add(str1);

str1:='';

end;

if length(trim(str2))>0 then begin

CurrentMemo2.Lines.Add(str2);

str2:='';

end;

end;

end;

end;

CurrentMemo1.Lines.Add('Сумма='+

inttostr(summn(CurrentTab.PageIndex,1)));

CurrentMemo2.Lines.Add(' Сумма='+

inttostr(summn(CurrentTab.PageIndex,2)));

end;

End.

В данной программе введены три особые переменные

CurrentTab: TTabSheet; CurrentMemo1:TMemo;

CurrentMemo2:TMemo;

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

КЛАССЫ

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

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

ИНКАПСУЛЯЦИЯ

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

· поля – служат для записи данных;

· методы – процедуры и функции для обработки полей;

· свойства – специальные методы, к которым можно обращаться как к полям.

Рассмотрим синтаксис объявления простейшего класса.

Type

TMyClass =class (TObject)

Public

AField: AType;

Procedure AMethod(Param: AType);

Function AFunc(Param: AType);AType;

Property AProperty: Atype read AField write AMethod;

End;

Объявленный выше класс включает одно поле AFieldкакого-либо типа, два метода AMethod, AFunc и одно свойство AProperty.

Объявление элементов класса делится на секции. В данном случае показана одна секция Public. Кроме Public могут присутствовать секции Protected, Published, Private. Эти секции задают разную степень видимости при обращениях из других модулей. Внутри модуля, являющегося владельцем класса, доступны все элементы из различных секций.

КЛАСС КАК ОБЪЕКТНЫЙ ТИП

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

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

В отличие от других типов class можно объявлять только глобально. Запрещено объявлять классы внутри процедур и функций.

НАСЛЕДОВАНИЕ

Правила объявления класса таковы, что любой класс обязательно должен быть связан с каким-либо другим классом (существует одно исключение – TObject, являющийся корнем иерархического дерева классов). Соответственно любой класс может использовать какие-либо свойства, поля, методы уже существующих классов. В объявлении класса выше после ключевого слова class указан сущесвующий класс TObject. Это означает, что тип TMyClass, кроме объявленных четырех элементов, содержит или наследует все элементы, содержащиеся в классе TObject. Класс TObject называется предком (родительским), а TMyClass – потомком (дочерним).

Наследование – вторая важная особенность объектных типов. Список наследников у данного класса может только возрастать. Каждый потомок может указать только одного предка. Однако неявно этот потомок содержит все поля, методы и свойства всех предков по линии наследования. Если предок не указан, то в Delphi считается, что предком является класс TObject.

ОБЛАСТИ ВИДИМОСТИ

Минимальную область видимости определяет секция Private. Вне модуля владельца данного класса элементы этой секции недоступны. В секцию Private следует помещать такие элементы, неосторожная модификация которых может привести к нежелательным последствиям. В секции Protected по сравнению с секцией Private защита элементов ослаблена. Элементы этой секции доступны только в классах потомках, в том числе и тогда, когда потомки создаются в другом модуле. Из секции Public элементы доступны в любом модуле, использующем данный класс. Если не указана область видимости, то по умолчанию принимается Published. Секция Published имеет область видимости такую же, что и секция Public. Отличие заключается в том, что эта секция имеет специальный интерфейс, благодаря которому информацию о членах этой секции может получить внешняя программа. Интерфейс Published используется инспектором объектов для визуализации компонентов. Если классы требуют интерфейса Published, то они относятся к типам времени выполнения RTTI (Ryntime Type Information).

ОПЕРАЦИИ IS И AS

Операции Is и As применяются к объектам. С помощью операции Is определяется, принадлежит ли данный объект указанному типу или одному из его потомков. Например, выражение AnObject is TMyClass возвращает true, если переменная AnObject совместима по присваиванию с переменной типа TMyClass. Для приведения типа какого-либо объекта применяется операция As. Например,

Наши рекомендации