Подпрограммы
Описание подпрограмм с их предварительным объявлением
Применение процедур и функций вышеописанными способами имеет некоторые недостатки. Во-первых, мы вынуждены описывать процедуры и функции выше того места, где будем их применять. Это связано с тем, что компилятор не будет знать про эти подпрограммы, если описать их ниже, и не сможет их выполнить. Собственно, вы не сможете даже скомпилировать такой проект. Во-вторых, в таких подпрограммах мы не сможем обращаться к свойствам компонентов. Если бы мы попытались из подпрограммы обратиться к той же Edit1.Text, то не смогли бы это сделать, хотя в событии нажатия на кнопку мы делаем это без труда. Дело в том, что события принадлежат к самой нашей форме, это видно по названию события:
procedure TfMain.Button3Click(Sender: TObject);
Видите, компилятор обращается вначале к форме, и только потом к самому событию? А вот в случае подпрограмм мы обращаемся напрямую к процедуре или функции. Но есть способ объявления подпрограммы, как части формы. Такой способ предоставляет нам следующие преимущества:
- Предварительно объявленную подпрограмму можно описывать в любом месте программы, не обязательно выше места её применения.
- В такой подпрограмме можно обращаться к свойствам и событиям компонентов.
- Подпрограмму можно описать как приватную, или как публичную. Приватную можно использовать только в текущем модуле (pas-файле). Публичную можно использовать в любом другом модуле, к которому подключается текущий.
Давайте посмотрим, как это делается на практике. Добавьте четвертую кнопку ниже предыдущих трех, с надписью в Caption
Пример удвоения №4
Сгенерируйте для неё событие нажатия на кнопку, в котором просто укажем вызов процедуры MyPrivat:
procedure TfMain.Button4Click(Sender: TObject); begin MyPrivat; end;
Это ничего, что самой процедуры еще нет, сейчас мы её объявим, а затем создадим. Поднимите курсор на начало модуля. Вы увидите раздел type, в котором есть объявление класса TfMain - нашей формы. А там объявлены все компоненты и сгенерированные нами ранее события OnClick. Ниже располагаются подразделы private и public, где мы можем объявлять подпрограммы соответственно, приватные и публичные. Давайте объявим процедуру MyPrivat в подразделе private:
Теперь, не убирая курсора с этой строки, нажмите клавиши <Ctrl + Shift + C>. Это приведет к тому, что в самом низу модуля (но перед завершающим "end.") сгенерируется описание процедуры MyPrivat. На самом деле, она могла бы быть сгенерирована где-то и в другом месте, всё зависит от того, в каком порядке указаны объявления всех событий и других подпрограмм. Посмотрите на рис. 9.4 - там MyPrivat объявлена последней, потому и сгенерировалось описание внизу модуля.
Никаких параметров нам в данном случае не нужно, мы будем обращаться к свойству Text компонента Edit1 прямо из нашей подпрограммы. И обратите внимание, в описании перед именем процедуры указано имя формы. Отредактируйте подпрограмму следующим образом:
procedure TfMain.MyPrivat; var r: real; begin //преобразуем в число то, что ввел пользователь: r:= StrToFloat(Edit1.Text); //теперь удвоим его: r:= r * 2; //теперь выведем результат в сообщении: ShowMessage(FloatToStr(r)); end;
Комментарии достаточно подробны, чтобы вы смогли разобраться с кодом. Подобный способ применения подпрограмм с предварительным объявлением является наиболее удобным, советую использовать именно его. Подпрограммы без предварительного объявления стоит использовать только в простейших случаях, когда, к примеру, нужно рассчитать какие-то данные, ну например, преобразовать значения температуры из шкалы в Фаренгейтах в шкалу по Цельсию. Тогда можно описать функцию подобного преобразования выше, и передавать в неё различные величины. Но даже и такую подпрограмму можно предварительно объявить!
Область видимости переменных
До сих пор мы не рассматривали переменные в этом аспекте. Просто объявляли их в подпрограммах, и использовали только внутри их. Такие переменные называются локальными, поскольку имеют локальную область видимости. Поясню. Переменная, объявленная внутри процедуры или функции, физически создается только тогда, когда компилятор обращается к данной подпрограмме. До этого переменной не существует. Только когда происходит вызов процедуры или функции, в оперативной памяти физически выделяется место для объявленных в подпрограмме переменных, констант и других объектов. Когда же подпрограмма завершает свою работу, то все эти переменные (константы и проч.) автоматически уничтожаются. К ним нельзя обратиться из других подпрограмм, их там просто не видно. Вот почему мы можем объявлять переменные с одинаковым именем в различных подпрограммах - это разные переменные, и они не мешают друг другу. Посмотрите на код нашего проекта - мы трижды объявляли переменную r вещественного типа, и каждый раз это была другая переменная.
Однако бывают моменты, когда требуется использовать глобальные переменные - переменные, которые видны по всему модулю, и в других модулях, если к ним подключается текущий. Такие переменные мы можем объявить либо в разделах private и public, до объявления подпрограмм, либо в разделе interface, после объявления переменной с именем формы, до ключевого слова implementation. Давайте объявим переменную MyNum:
Теперь добавим на форму пятую кнопку, текст в Caption будет соответствующий. Сгенерируйте для неё событие OnClick. Обратите внимание, оно создалось выше предыдущей процедуры MyPrivat, поскольку объявления различных событий располагаются выше разделов private и public. Опишем событие следующим образом:
procedure TfMain.Button5Click(Sender: TObject); begin MyNum:= StrToFloat(Edit1.Text); //теперь удвоим его: MyDouble; //выводим результат на экран: ShowMessage(FloatToStr(MyNum)); end;
Обратите внимание: переменную MyNum мы в событии не объявляем - она уже объявлена глобально, и ей можно пользоваться в любом месте модуля. Процедуры MyDouble ещё нет, объявим её в разделе private ниже MyPrivat:
procedure MyDouble; //удвоение глобальной переменной
Далее сгенерируем описание этой процедуры (<Ctrl + Shift + C>). Само описание будет очень простым:
procedure TfMain.MyDouble; begin //удвоим глобальную переменную: MyNum:= MyNum * 2; end;
Как видите, здесь мы работаем с той же глобальной переменной, не объявляя её внутри процедуры, поскольку она уже объявлена.
Глобальные переменные очень удобны, однако используйте их только там, где это действительно необходимо. Ведь память для глобальной переменной выделяется, когда вы загружаете программу, и не освобождается, пока вы программу не закроете.
Досрочный выход из подпрограмм и программы
Иногда бывает необходимо срочно завершить процедуру или функцию. К примеру, в зависимости от каких то условий, вам требуется либо продолжать обработку данных, либо закончить подпрограмму и вывести готовый результат. Для этого существует ключевое слово Exit. Запомните: если в подпрограмме встретилось exit, подпрограмма досрочно завершает свою работу и компилятор передает управление следующему за вызовом подпрограммы оператору.
Если же встретится ключевое слово Halt, то уже вся программа досрочно завершает свою работу. Она закрывается, память, занимаемая программой, освобождается, а управление передается операционной системе. Чаще всего эту команду применяют для аварийного завершения работы.
Сейчас мы не будем применять эти операторы на практике, поскольку лекция итак получилась очень большой. При желании, вы можете опробовать их самостоятельно, в каких то из уже сделанных подпрограмм, или в новых. В дальнейшем мы не раз будем обращаться к этим операторам, по крайней мере, к оператору Exit.