
- •Министерство образования и науки рф
- •Введение
- •Требования к оформлению отчета*
- •Задания к лабораторным работам.
- •Лабораторная работа 2. Методы численного интегрирования.
- •Указания и требования к выполнению работы.
- •Методы численного интегрирования
- •Лабораторная работа № 3. Расчет реактора смешения для сложной реакции с линейной кинетикой
- •Требования по выполнению работы:
- •Замечания по выполнению работы.
- •Реактор идеального смешения
- •Методы решения систем линейных алгебраических уравнений.
- •Метод Жордана-Гаусса (обращения матриц).
- •Итерационные методы.
- •Лабораторная работа № 4
- •4.1 Обработка экспериментальных данных по парожидкостному равновесию.
- •Обработка экспериментальных данных.
- •38 Метанол-ацетон-гептан
- •43 Метанол-ацетон-циклогексан
- •1. Интерполирование.
- •2. Метод наименьших квадратов
- •4.2. Расчет температуры кипения и точки росы трехкомпонентной смеси.
- •Методы уточнения корней уравнений с одним неизвестным.
- •Расчет производится по следующим
- •Лабораторная работа 5 Расчет реактора идеального вытеснения
- •Требования по выполнению работы:
- •Методы решения обыкновенных дифференциальных уравнений
- •Лабораторная работа № 6 Исследование функции, нахождение ее характерных точек и ее графическое изображение в трехмерных координатах.
- •Содержание
- •Приложение –1 – описание языка турбо паскаль версия № 7.0
- •1. Алфавит языка
- •1.1. Символы, используемые в идентификаторах
- •1.2. Разделители.
- •1.3.2. Знаки операций
- •1.3.3. Зарезервированные слова
- •1.4. Неиспользуемые символы
- •2. Структура программы
- •3. Типы данных
- •3.1. Классификация типов данных
- •3.2. Простые типы данных
- •3.2.3. Символьный тип
- •3.2.4. Перечисляемый тип
- •3.2.6. Вещественные типы
- •4. Выражения
- •4.1. Переменные
- •4.2 .Константы.
- •4.2.1. Целые константы
- •4.2.4. Константные выражения
- •4.2.5. Типизированные константы
- •4.3. Стандартные функции
- •4.3.1. Арифметические функции
- •4.3.2. Функции преобразования типа
- •4.3.3. Функции для величин порядкового типа
- •4.4. Знаки операций
- •4.4.1. Арифметические операции
- •4.4.2. Логические операции
- •4.4.3. Операции с битами информации
- •4.4.4. Операции отношения
- •4.5. Круглые скобки
- •4.6. Порядок вычисления выражений
- •5. Операторы языка
- •5.1. Простые операторы
- •5.1.1. Оператор присваивания
- •5.1.2. Оператор безусловного перехода gото. Использование меток
- •5.1.3. Пустой оператор
- •5.2. Структурированные операторы
- •5.2.1. Составной оператор
- •5.2.2. Условный оператор if
- •5.2.3. Условный оператор саsе
- •5.2.4. Оператор цикла repeat
- •5.2.5. Оператор цикла while
- •5.2.6. Оператор цикла for
- •5.2.7. Использование стандартных процедур Break и Соntinue в операторах циклов repeat, while и for
- •6. Структурированные типы данных
- •6.1. Массив
- •6.2. Строка типа string
- •6.3. Аsciiz-строка
- •6.4. Запись
- •6.5. Множество
- •6.6. Файл
- •7 Динамические структуры — данных
- •7.1. Указатель
- •7.2. Работа с динамической памятью
- •7.3. Работа со структурами данных
- •8. Процедурные типы
- •9. Совместимость и преобразование типов данных
- •10 Процедуры и функции
- •10.1. Процедура
- •10.2. Функция
- •10.3. Формальные и фактические параметры
- •10.3.1 Параметры-значения
- •10.3.2. Параметры-переменные
- •10.3.3. Параметры-константы
- •10.3.4. Параметры без типа
- •10.3.5. Массивы и строки открытого типа
- •10.3.6. Параметры-процедуры и параметры-функции
- •10.4. Процедура еxit
- •10.5. Директивы подпрограмм
- •10.5.1. Директива forward
- •10.5.2. Директивы fаr и near
- •10.5.3. Директива ехтеrnal
- •10.5.4. Директива аssembler
- •Пример. Функция, определяющая максимальное из двух чисел
- •10.5.5. Директива inline
- •10.5.6. Директива interrupt
- •10.6. Рекурсивные процедуры и функции
- •11 Организация ввода-вывода
- •11.1. Стандартные процедуры и функции для всех файлов
- •Функции
- •11.2. Стандартные процедуры и функции для текстовых файлов
- •11.3. Стандартные процедуры и функции для типизированных файлов
- •Осуществляется настройка на элемент файла, с которым связана файловая переменная f. Элемент файла определяется номером №, причем нумерация элементов начинается с нуля.
- •11.4. Стандартные процедуры и функции для файлов без типа
- •11.5. Внешние устройства в качестве файлов
- •12 Объектно-ориентированное программирование в turbo pascal 7.0
- •12.1. Пример использования ооп
- •12.2. Понятие объекта
- •12.2.2. Наследование
- •12.2.3. Полиморфизм
- •12.3. Виртуальные методы
- •13 Модули
- •13.1. Заголовок модуля
- •13.2. Интерфейс модуля
- •13.3. Исполнительная часть модуля
- •13.4. Секция инициализации
- •13.5. Использование модуля в основной программе
- •13.6. Использование идентификаторов элементов модуля
- •14 Стандартные модули
- •14.1 Модуль System
- •Арифметические функции
- •Процедуры работы со строками
- •Функции работы со строками
- •Функции управления вводом-выводом
- •Процедуры управления вводом-выводом
- •Функции управления динамической памятью и адресные функции
- •Include Включение элементов множества
- •14.2. Модуль String
- •14.3. Модуль Сrt
- •C80 с080 Для совместимости с версией 3.0
- •14.4. Модуль Graph
- •14.4. Пример использования подпрограмм модуля Сrарh
12.3. Виртуальные методы
В ряде случаев при описании тех или иных схожих объектов приходится писать методы, также схожие друг с другом и отличающиеся только отдельными деталями. Так, в рассматриваемом примере методы объектов типа tLine (строка) и типа tТехt (текст), предназначенные для создания соответствующего элемента и включения его в структуру, выполняют одинаковый набор действий: выделяют место в динамической области памяти и размещают там соответствующий объект, а затем устанавливают соответствующие связи этого объекта в структуре текста. При этом установление связей в структуре вообще не зависит от типа создаваемого объекта (здесь необходимо установить связи с предыдущим и последующим элементом и в случае необходимости объявить новый элемент первым или последним в структуре - эти операции практически не зависят от типа элемента). Однако, операция выделения памяти и размещения в ней соответствующего объекта существенно зависит от его типа. Таким образом, для объекта типа tLine этот метод можно было бы написать следующим образом:
рrосеdure tLine.NewЕl(РоintРrеdЕl, РоintNextЕ1: Роinter); {РоintРrеdЕl - указатель на предыдущий элемент в структуре, РоintNextEl - указатель на последующий элемент в структуре}
var NewPiont: Роinter {указатель, на новый элемент}
begin
NewPoint:=InitElem;
РutСоnnection(PointPredЕl, NewРоint);
РutСоnnection(NewPoint, PointNextEl);
еnd;
В этом методе первая строка (NеwРоint:= InitElem) - обращение к методу, выделяющему соответствующую область динамической памяти и размещающему там элемент строки, одновременно заполняя его строку информации Info пробелами. Две последующие сроки - обращение к методу РutСоnnection, устанавливающему связи между двумя элементами структуры (в данном случае - элементами строк). Эти два обращения устанавливают связи нового элемента строки с ее соседями: предыдущим и последующим элементами.
Если написать подобный метод для создания нового текста, то отличие будет в методе InitElem, который должен выделить место для объекта типа tLinе (строка), разместить его в этой области и создать начальный элемент строки.
Хотя написание двух методов NewЕl для строки и всего текста эквивалентно их нельзя объединить в один и поместить в объект - предок, т. к. обращение InitElem у них представляет обращение к различным методам. Это неудобство можно обойти, объявив методы InitElem виртуальными. В этом случае, действительно, можно написать только один метод NеwЕl, а то, какой из методов InitЕlеm будет выбираться в каждом конкретном случае, зависит от того, какой объект будет создаваться.
Объявление виртуальных методов
Чтобы объявить метод виртуальным, при описании типа-объекта после указания заголовка этого метода следует записать зарезервированное слово virtual:
tyре
tLinе = оbject(tStructure)
…
function InitЕlеm: Роinter; virtual;
еnd;
tТехt = оbject(tSructure)
…
function InitЕlеm: Роinter; virtual;
еnd;
Если метод где-то был объявлен виртуальным, то и все другие методы с тем же заголовком также должны быть объявлены виртуальными. Естественно, что у всех таких методов списки формальных параметров (и тип функции, если метод является подпрограммой-функцией) должны быть эквивалентными.
Метод, использующий виртуальные методы, должен быть размещен в объекте, доступном всем объектам, где этот метод должен применяться. Так, в нашем примере метод NеwEl используется в объектах типов tLine и tТехt, которые являются непосредственными потомками абстрактного типа tStructure, поэтому естественно NewEl описать в типе tStructure, что и сделано в примере. Однако в этом случае тип tStructure должен также содержать виртуальный метод InitElem. Но в связи с тем, что объект типа tStructure является абстрактным, этот метод не должен явно выполнять никаких действий (в каком-то смысле является фиктивным) и имеет вид:
function tStructure.InitЕlеm: Роintеr;
begin
еnd;
Конструкторы и деструкторы.
Основное отличие виртуальных методов заключается в том. что необходимые связи с ними в программе устанавливаются не на этапе компиляции и компоновки, а на этапе выполнения программы. С этой целью у объекта создаются таблицы виртуальных методов, куда записываются адреса всех используемых в этом объекте виртуальных методов. При выполнении программы в случае необходимости из этой таблицы выбирается адрес соответствующего варианта виртуального метода с целью использования именно этого варианта. Однако для использования такой таблицы предварительно ее следует заполнить этими адресами. Для этой цели применяются специальные методы, которые называются конструкторами (соnstructor). Такой метод должен быть использован в программе до того, как будет обращение к виртуальному методу. Формальное отличие конструктора от обычного метода заключается в том, что вместо зарезервированного слова рrocedure используется зарезервированное слово соnstructor. Основное назначение конструктора - записать адрес виртуального метода в таблицу виртуальных методов, однако он может выполнять и другие действия по инициализации создаваемого объекта: устанавливать необходимые связи, задавать начальные условия и: т. д. Так, в рассматриваемом примере конструктор тепа tLine (cтрока) формирует начальный элемент создаваемой строки и имеет вид:
Соnstructor tLine.Init;
begin
NewElem(nil, nil)
еnd;
Т. к. использовать конструктор следует в программе как можно раньше (во всяком случае до первого использования виртуального метода), то целесообразно его использование объединить непосредственно с созданием конкретного объекта. С этой целью в Тurbo Раscal стандартная процедура New дополнена вторым необязательным параметром - именем конструктора создаваемого объекта. Так, в секции инициализации модуля, выполняемой при запуске программы, при создании объекта типа tТехt указатель на этот объект записывается в переменную РоintТехt одновременно происходит инициализация этого объекта конструктором Init:
New(PointТехt, Init);
Если при создании какого-либо объекта инициализировать его не нужно, а объект, тем не менее, содержит виртуальные методы, конструктор все-таки должен быть. Однако в этом случае он представляет собой пустую подпрограмму, не выполняющую явно никаких действий (см. соnstructor InsertUp.Init или подобные ему), но заносящую информацию в таблицу виртуальных методов.
Аналогичным образом при удалении из динамической области памяти размещенного там объекта в процедуре Dispose можно использовать подпрограмму, называемую деструктором (destructor), предназначенную для выполнения различных операций, связанных с ликвидацией объекта (исключение его из списка, задание параметров, очистка данных и т. д.). Деструктор, как правило, наследуется потомками и обычно бывает виртуальным.
Возможности модификации программы при иcпользовании виртуальных методов
Одна из причин использования виртуальных методов - возможность упрощения написания программы за счет устранения повторяющихся частей - уже упоминалась. Однако, по-видимому, это не основная причина введения виртуальных. методов. Действительно, устранить упоминавшийся недостаток можно и другим способом: используя параметры процедурного типа. Другая, более существенная причина заключается в возможности модификации виртуальных методов или расширения функций программы без ее глобальной перекомпиляции. Внести изменения в обычный метод без перекомпиляции программы невозможно, для виртуального же метода можно либо внести какие-то изменения, либо полностью его заменить.
Предположим, что в рассматриваемом примере реакцию программы на клавишу Dn следует изменить таким образом, чтобы при отсутствии очередной строки эта строка создавалась и курсор переходил бы на эту строку (заметим, что в первоначальном варианте в таком случае никаких изменений не происходит). В этом случае метод, обрабатывающий нажатие клавиши Dn, должен сначала создать новую строку, а затем осуществить перевод курсора на эту новую строку. Основную программу в этом случае можно написать, например, следующим образом:
usesСrt, Еdit; {*** Новая обработка клавишиDn***}
tyре
рInsertMyDn=^tInsertMyDn; {указатель на новый тип}
tInsertMyDn = object(tInsertDn) {новый тип}
соnstructor Init;
рrосеdure Ins; virtual;
еnd;
var Dn1: рInsertMyDn; {новая переменная}
соnstructortInsertМуDn.Init; {конструктор переменной нового типа}
begin
еnd;
рrосеduretInsertMyDn.Ins; {новый метод}
begin
with PointText^ do
if GetPointLine(GetY+1) = nil then {если нет следующей строки...}
NewEl(GetLastElem, nil); {- создать ее}
Insert.Ins{переместить курсор}
end;
{*** Основная программа ***}
begin
New(Dn1,Init); {создание нового объекта}
ТеxtBackGround(Blue);
ТeхtСоlоr(White);
СlrScr;
GotoXY(1, 1);
with PointText^ do
repeat
Сh := ReadКеу;
if Сh = Сhr(0) then
begin
Сh := ReadКеу;
case Ord(Ch) of
72: Up^.РutNewSymb;
80: Dn1^.РutNewSymb; (обращение к новому методу}
75: Left^.РutNewSymb;
77: Right^.РutNewSymb;
еnd
end
else if Сh >Сhr(31) then Symbol^.РutNewSymb
еlse if Ch=Сhr(Ent) then Еnter^.РutNewSymb
else if Сh=Сhr(ВасkS) then ВаскSpace^.РutNewSymb
until Сh = Сhr(Esc);
Dispose(РоintТехt, Done);
ТехtВасkground(Вlack);
СlrScr
еnd.
Здесь введен новый тип tInsertMyDn, являющийся наследником типа tInsertDn. Его виртуальный модуль Ins сначала создает новую строку, если ее нет, а затем обращается к уже существующему методу tInsertDn.Ins для перемещения курсора в новое положение. Изменена в тексте и строка, где происходит обращение к методу обработки клавиши Dn.
Заметим, что все изменения в этом случае можно сосредоточить в основной программе, не меняя и не компилируя модуль повторно.
Следует обратить внимание еще на. один момент, связанный .с методом tInsertMyDn.Ins. Этот метод сначала выполняет какие-то свои операции, а затем вызывает аналогичный метод своего предка. Такая ситуация допустима и встречается довольно часто. Это также позволяет несколько сократить программу, не программируя повторно операции метода предка. Т.к. эта ситуация встречается довольно часто, в версии 7.0 допустимо при обращении к методу непосредственного предка не указывать его тип, а заменить его зарезервированным словом inherited. Так, в предыдущем примере рассматриваемый метод можно также записать следующим образом:
рrосеdure tInsertMyDn.Ins; {новый метод}
begin
with РоintТехt^do
if GetPointLine(GetY + 1)= nil then {если нет следующей строки…}
NewEl(GetLastElem, nil); {- создать ее}
InheritedIns{переместить курсор}
еnd;
Когда необходимо решать, делать ли метод виртуальным, следует учитывать, возможны ли в дальнейшем изменения этого метода, и, если они возможны, его следует объявить виртуальным. Однако и злоупотреблять виртуальными методами не следует, т. к. их использование увеличивает размер программы за счет таблиц виртуальных методов и уменьшает быстродействие, т.к. в этом случае при обращении к виртуальному методу сначала в таблице ищется его адрес, а затем уже происходит обращение к методу.
Виртуальные методы следует использовать и в том случае, когда возможно расширение функций программы. Так в рассматриваемом примере, конечно, можно ожидать расширения количества клавиш, обрабатываемых редактором. В связи с этим все методы обработки тех или иных клавиш объявлены виртуальными. Это позволяет довольно просто добавлять объекты обработки новых клавиш опять - таки без перекомпиляции уже созданного модуля. Так, в случае, когда необходимо дополнительно обрабатывать клавиши Ноme и Еnd, основная программа может выглядеть, например, следующим образом:
uses Crt, Edit;
(* * * Обработка клавиш Ноmе и Еnd * * *}
type
pInsertHome = ^tInsertHome; {указатель на новый тип}
tInsertHome = object(tText) {новый тип}
constructor Init;
procedure Ins; virtual
end;
pInsertEnd = ^tInsertEnd; {указатель на новый тип}
tInsertEnd = object(tText) {новый тип}
constructor Init;
procedure Ins; virtual
end;
var Home: pInsertHome; {новая переменная}
Endd: pInsertEnd; {новая переменная}
constructor tInsertHome.Init; {конструктор переменной нового типа}
begin
end;
procedure tInsertHome.Ins; {новый метод}
begin
with PointText^ do
PutX(l)
end;
constructor tInsertEnd.Init; {конструктор переменной нового типа}
begin
end;
procedure tInsertEnd.Ins; {новый метод}
var PointElLine: pElLine;
NomAbs: Word;
NomInEl: Byte;
begin
with PointText^ do
begin
CurrentPointLine^.LastNotBlank(PointElLine, NomAbs.NomInEl);
PutX (NomAbs + 1)
end
end;
( * * Ocновная пpoгрaмма * * *}
begin
New(Home, Init); {создание нового объекта}
New(Endd, Init); {создание нового объекта}
TextBackGround(Blue);
TextColor(White);
GotoXY(1, 1);
with PointText^ do
repeat
Ch = ReadKey;
if Ch = Chr(0) then
begin
Ch := ReadKey;
case Ord(Ch) of
72 Up^.PutNewSymb;
80 Dn^.PutNewSymb;
75 Left^.PutNewSymb;
77 Right^.PutNewSymb;
71 Home^.PutNewSymb; {Обработка клавиши Ноmе}
79 Endd^.PutNewSymb {Обработка клавиши Еnd}
end
end
else if Ch > Chr(31) then Symbol^.PutNewSymb
else if Ch = Chr(Ent) then Enter^.PutNewSymb
else if Ch = Chr(BackS) then Backspace^.PutNewSymb
until Ch = Chr(Esc);
Dispose(PointText, Done);
TextBackGround(Black);
ClrScr
end.