Файл: А.Г. Пимонов Основы объектно-ориентированного программирования в среде Турбо Паскаль.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 31.05.2024
Просмотров: 30
Скачиваний: 1
МИНИСТЕРСТВО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ
ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ «КУЗБАССКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ»
Кафедра вычислительной техники и информационных технологий
ОСНОВЫ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ В СРЕДЕ ТУРБО ПАСКАЛЬ
Методические указания к лабораторной работе по дисциплине «Информатика и программирование» для студентов специальности 351400 «Прикладная информатика в экономике»
Составители А.Г. Пимонов Д.Л. Крутский
Утверждены на заседании кафедры Протокол №7 от 10 марта 2003 г.
Рекомендованы к печати учебно - методической комиссией специальности 351400 Протокол №3 от 10 марта 2003 г.
Электронная копия хранится в библиотеке главного корпуса ГУ КузГТУ
КЕМЕРОВО 2003
1
1. ОБЪЕКТНО-ОРИЕНТИРОВАННАЯ МЕТОДОЛОГИЯ РАЗРАБОТКИ ПРОГРАММНЫХ КОМПЛЕКСОВ
Объектно-ориентированная концепция создания программ зародилась примерно в одно и то же время со структурной методологией (примерно в середине 60-х годов) и имела аналогичную цель – обеспечение дисциплины программирования при разработке больших программных комплексов. По определению известного программиста Гради Буча «объектно-
ориентированное программирование (ООП) – это методология программи-
рования, которая основана на представлении программы в виде совокупности объектов, каждый из которых является реализацией определенного класса (типа особого вида), а классы образуют иерархию на принципах наследуемости». ООП базируется на трех основных понятиях: инкапсуляция, на-
следование и полиморфизм.
Определений понятия объект существует достаточно много. С точки зрения Гради Буча: «Объект – осязаемая сущность, которая четко проявляет свое поведение». Не лишен скрытого смысла студенческий ответ: «Объект – это все». Инкапсуляция – это объединение в рамках единого целого (объекта) данных (характеристик объекта) и действий (процедур и функций) по обработке этих данных. В терминах ООП данные называются полями, а процедуры и функции – методами. То есть можно сказать, что объект состоит из полей и методов. Инкапсуляция позволяет в максимальной степени изолировать объект от внешнего окружения. Объект (а точнее – экземпляр объекта) сам «знает» о себе все и «умеет» манипулировать этими знаниями. При этом обмен данными между объектом и программой (или другим объектом) сведен к минимуму.
Наследование – это свойство объектов порождать своих потомков. По Гради Бучу «наследование – это такое отношение между объектами, когда один объект повторяет структуру и поведение другого». Объект-потомок автоматически наследует от родителя все поля и методы, может быть дополнен новыми полями, а методы предка могут быть заменены или дополнены новыми. Объект может иметь сколько угодно потомков, а вот предок может
2
быть только один. Это дает возможность создавать довольно-таки сложную «ветвистую» (древовидную) иерархическую структуру объектов в программе.
Полиморфизм – это свойство родственных объектов (то есть объектов, имеющих общего родителя) решать схожие задачи разными способами. Поскольку поведение объекта определяется набором его методов, то программист, изменяя алгоритм того или иного метода, может придавать потомкам специфические свойства, отсутствующие у родителя. Для этого родительский метод должен быть перекрыт новым. В результате объект-родитель и объект-потомок будут содержать два разных метода, но с одинаковыми именами. В Turbo Pascal полиморфизм достигается не только за счет наследования и перекрытия методов, но и использованием виртуальных методов.
2. ОБЕКТНО-ОРИЕНТИРОВАННЫЕ СРЕДСТВА ЯЗЫКА TURBO PASCAL
2.1. Объектные типы и экземпляры объектов
Переменные объектных типов (экземпляры объектов) с точки зрения Turbo Pascal представляют собой структурированный (комбинированный) тип данных, являющихся совокупностью информационных полей (переменных любого типа) и методов (процедур и функций). Объектные типы описываются в разделе Type программы с использованием зарезервированного (ключевого) слова object:
Type
<имя объектного типа> = object <информационные поля объекта (переменные)>
<методы объекта (заголовки процедур и функций)> end;
Например, опишем объект, который будет представлять собой позицию на графическом экране. Нам понадобится объявить два поля (X и Y- координаты точки) и несколько методов: для инициализации объекта, получения его координат, уничтожения и т. п.
Type
TLocation = object
X,Y : Word; {Координаты позиции на экране}
3
Procedure Init(InitX, InitY : Integer); {Инициализация объекта}
Function GetX : Word; {Возвращает координату Х} Function GetY : Word; {Возвращает координату Y} Procedure GetCoords(Var CoordX, CoordY : Word);
{Возвращает обе координаты}
Procedure Done; {Уничтожает объект} End;
Как видно из примера, поля объекта описываются таким же образом, что и поля записи, а для описания методов объекта используются только заголовки процедур и функций. Само собой разумеется, что такой объект никому не нужен, поскольку не реализована его функциональность (то есть – не описаны тела процедур и функций). Тела методов всех объектов, объявленных в программе, описываются в разделе реализации процедур и функций программы (в любом месте и в любой последовательности, но обязательно ниже «своего» объекта). Синтаксически реализация метода выглядит так же, как и реализация «обычной» процедуры или функции за одним исключением: перед именем метода через точку необходимо указать имя объекта, которому он принадлежит:
Procedure <Имя объекта>.<Имя метода>(<Формальные
параметры>);
<Раздел локальных описаний метода (процедуры)> begin
<Операторная часть метода (тело процедуры)> end;
Опишем методы объекта TLocation:
Procedure TLocation.Init(X,Y : Word); begin
X := InitX;
Y := InitY end;
Function TLocation.GetX : Word; begin
GetX := X end;
4
Function TLocation.GetY : Word; begin
GetY := Y end;
Procedure TLocation.GetCoords; begin
CoordX := GetX;
CoordY := GetY end;
Procedure TLocation.Done; begin
end;
Хотим обратить ваше внимание на несколько моментов: во-первых, при реализации методов не обязательно повторять весь заголовок подпрограммы, достаточно только имени без списка формальных параметров (как это сделано для метода GetCoords), во-вторых, метод объекта может обращаться не только к полям, но и к другим методам (как это сделано во все том же методе GetCoords), и, в-третьих, в данном объекте присутствует метод Done (пустой), который «ничего не делает», поскольку позицию на экране уничтожить нельзя.
2.2.Директивы private и public
Спомощью директивы private при описании объекта можно ограничить область видимости полей и методов. Поля и методы объекта, описанные в секции private, будут доступны только в пределах той программной единицы (программы или модуля), где описан соответствующий объект. Такие поля и методы принято называть приватными. То есть если описать объект TLocation следующим образом:
Type
TLocation = object private
X, Y : Word; public
…
end;
и разместить это описание в модуле, то после подключения модуля к программе программист не сможет «напрямую» изменять значения этих полей
5
(X, Y). Он будет вынужден вызывать соответствующие методы. По умолчанию поля и методы, описанные непосредственно за ключевым словом object, считаются общедоступными. Директива же public просто отменяет действие директивы private. То есть все последующие поля и методы будут общедоступными.
Директивы private и public могут использоваться в любом порядке сколько угодно раз, но принято при описании объектного типа после зарезервированного слова object объявлять общедоступные поля и методы и только затем после директивы private – приватные.
2.3. Наследование
Если объектный тип создается «на базе» другого существующего объекта, то имя родительского типа должно быть указано в скобках после слова object при описании потомка:
Type
<Потомок> = object(<Родитель>) <Добавленные поля>
<Добавленные и переопределенные методы> end;
Как уже говорилось выше, такие объекты автоматически наследуют от родителя его поля и методы. Поля могут быть добавлены (но не переопределены), а методы переопределены и добавлены.
Создадим новый объект – точку на основе существующего объекта – позиции на графическом экране. Новый объект, кроме координат, будет характеризоваться еще и цветом, может быть видимым или невидимым, перемещаться по экрану. Для этого нам понадобится добавить два свойства и несколько методов, а также переопределить методы Init и Done:
Type
TPoint = object(TLocation) Clr : Byte; {Цвет}
Visib : Boolean; {Видимость}
Procedure Init (InitX, InitY:Word; InitColor:Byte);
{Переопределяем метод инициализации – добавляем цвет} Function GetColor : Byte; {Возвращает цвет}
Function IsVisib : Boolean; (Возвращает видимость}
6
Procedure Show; {Делает видимым} Procedure Hide; {Делает невидимым}
Procedure ChangeColor(NewColor : Byte); {Меняет цвет} Procedure MoveTo(NewX, NewY : Word);
{Перемещает в новую позицию}
Procedure Done;
{Переопределяем для уничтожения объекта} end;
Теперь напишем реализацию методов:
Procedure TPoint.Init (InitX, InitY:Word; InitColor:Byte);
begin
X := InitX;
Y := InitY;
Clr := InitColor;
Visib := False end;
Как видите, этот метод добавляет новую функциональность по сравнению с предыдущим. Первые две строки тела метода повторяют (причем полностью) операторную часть метода Init объекта TLocation, две следующие – новые. И хотя такой вариант переопределения метода тоже работоспособен, в данном случае его можно упростить с помощью такого механизма, как вызов метода непосредственного родителя из метода потомка. Для этого в Turbo Pascal есть специальное зарезервированное слово inherited (в переводе с английского – унаследованный), которым мы и воспользуемся:
Procedure TPoint.Init (InitX, InitY:Word;
InitColor:Byte);
begin
inherited Init(InitX, InitY); Clr := InitColor;
Visib := False end;
Текст стал несколько короче. Это будет особенно заметно при дальнейшем наследовании. Вместо слова inherited можно указать имя объек-
та-родителя: TLocation.Init(InitX, InitY);
Продолжим:
Function TPoint.GetColor : Byte; begin
7
GetColor := Clr; end;
Procedure TPoint.Show; begin
Graph.PutPixel(X, Y, Clr);
Visib := True end;
Procedure TPoint.Hide; begin
Graph.PutPixel(X, Y, Graph.GetBkColor); Visib := False
end;
Procedure TPoint.IsVisib : Boolean; begin
IsVisib := Visib end;
Procedure TPoint.ChangeColor(NewColor : Byte); begin
Clr := NewColor;
If IsVisib then Show end;
Procedure TPoint.MoveTo(NewX, NewY : Word); Var Status : Boolean;
begin
Status := IsVisib;
Hide;
X := NewX;
Y := NewY;
If Status then Show end;
Procedure TPoint.Done; begin
Hide;
Clr := Graph.GetBkColor end;
Дочерний объектный тип «точка» – потомок родительского объекта «позиция» создан.
8
2.4. Полиморфизм, виртуальные методы и конструкторы
Создадим еще один дочерний объектный тип – потомок объекта TPoint, который будет представлять собой окружность. X и Y соответственно превращаются в координаты центра, и добавляется радиус. Само собой разумеется, придется переопределить методы инициализации, прорисовки и скрытия.
Type
TCircle = object(TPoint) R : Word;
Procedure Init(InitX, InitY, InitR:Word; InitC:Byte);
Procedure Show;
Procedure Hide;
Procedure Done; end;
Procedure TCircle.Init(InitX, InitY, InitR : Word;
InitColor : Byte);
begin
inherited Init(InitX, InitY, InitC);
R := InitR end;
Procedure TCircle.Show; begin
Graph.SetColor(Clr);
Graph.Circle(X, Y, R);
Visib := True end;
Procedure TCircle.Hide; begin
Graph.SetColor(Graph.GetBkColor);
Graph.Circle(X, Y, R); Visib := False
end;
Procedure TCircle.Done; begin
inherited Done; R := 0
end;
Таким образом, мы получили два объекта, методы которых Show и Hide делают одно и то же, но разными способами (полиморфизм).
Но вот непредвиденные последствия. Если мы создадим экземпляр
9
этого объекта, проинициализируем его, а затем попытаемся переместить вызовом метода MoveTo, который был унаследован, то переместится точка, а не окружность. Связано это с тем, что при компиляции в машинный код вместо вызова подпрограммы транслятор подставляет адрес точки входа в эту подпрограмму. Это же справедливо и для методов, поэтому при трансляции метода MoveTo объекта TPoint будут подставлены адреса точек входа методов Show и Hide объекта TPoint. Объект же TCircle наследует метод MoveTo, но не переопределяет его. Поэтому при вызове метода MoveTo экземпляром объекта TCircle он, в свою очередь, вызовет методы Show и Hide объекта TPoint, то есть – переместит точку, а не окруж-
ность.
Избежать этого можно двумя способами. Во-первых, каждый раз переопределять метод MoveTo, чтобы транслятор всегда компилировал его заново. Однако это не совсем удобно, поскольку эти методы ничем не будут отличаться. Второй способ – объявить методы Show и Hide виртуальными.
При компиляции объекта, содержащего виртуальные методы, создается так называемая таблица виртуальных методов (ТВМ), содержащая адрес точки входа каждого из виртуальных методов, а в месте вызова такого метода ставится ссылка на ТВМ. При обращении к виртуальному методу компьютер сначала «смотрит», экземпляр какого именно объекта обратился к этому методу, затем «ищет» адрес точки входа виртуального метода именно этого объекта и запускает его. Все это происходит уже на этапе выполнения программы и поэтому называется поздним (динамическим) связыванием. Ранним связыванием называется процесс статического связывания методов с реализациями (экземплярами) объектов. Раннее связывание осуществляется на этапе компиляции для всех статических методов. Для объявления виртуального метода используется зарезервированное слово (директива) virtual.
Итак, переписываем объявления методов TPoint и TCircle: