В основе того или иного языка программирования лежит некоторая руководящая идея, оказывающая существенное влияние на стиль соответствующих программ.
Исторически первой была идея процедурного структурирования программ, в соответствии с которой программист должен был решить, какие именно процедуры он будет использовать в своей программе, а затем выбрать наилучшие алгоритмы для реализации этих процедур. Последовательное использование идеи процедурного структурирования программ привело к созданию обширных библиотек программирования, содержащих множество сравнительно небольших процедур, из которых, как из кирпичиков, можно строить “здание” программы.
По мере прогресса в области вычислительной математики акцент в программировании стал смещаться с процедур в сторону организации данных. Оказалось, что эффективная разработка сложных программ нуждается в действенных способах контроля правильности использования данных. Контроль должен осуществляться как на стадии компиляции, так и при прогоне программ, в противном случае, как показала практика, резко возрастают трудности создания крупных программных проектов. Отчетливое осознание этой проблемы привело к созданию Алгола—60, а позже — Паскаля, Модулы—2, Си и множества других языков программирования, имеющих более или менее развитые структуры типов данных.
Начиная с языка Симула—67, в программировании наметился новый подход, который получил название объектно—ориентированного программирования (ООП). Его руководящая идея заключается в стремлении связать данные с обрабатывающими эти данные процедурами в единое целое — объект. Характерной чертой объектов является инкапсуляция (объединение) данных и алгоритмов их обработки, в результате чего и данные, и процедуры во многом теряют самостоятельное значение. Фактически объектно—ориентированное программирование можно рассматривать как модульное программирование нового уровня, когда вместо во многом случайного, механического объединения процедур и данных акцент делается на их смысловую связь.
Какими мощными средствами располагает объектно—ориентированное программирование наглядно демонстрирует библиотека Turbo Vision, входящая в комплект поставки Турбо Паскаля.
Следует заметить, что преимущества ООП в полной мере проявляются лишь при разработке достаточно сложных программ.
Основные принципы ООП
Объекты
В основе того или иного языка программирования лежит некоторая руководящая идея, оказывающая существенное влияние на стиль соответствующих программ.
Исторически первой была идея процедурного структурирования программ, в соответствии с которой программист должен был решить, какие именно процедуры он будет использовать в своей программе, а затем выбрать наилучшие алгоритмы для реализации этих процедур. Последовательное использование идеи процедурного структурирования программ привело к созданию обширных библиотек программирования, содержащих множество сравнительно небольших процедур, из которых, как из кирпичиков, можно строить “здание” программы.
По мере прогресса в области вычислительной математики акцент в программировании стал смещаться с процедур в сторону организации данных. Оказалось, что эффективная разработка сложных программ нуждается в действенных способах контроля правильности использования данных. Контроль должен осуществляться как на стадии компиляции, так и при прогоне программ, в противном случае, как показала практика, резко возрастают трудности создания крупных программных проектов. Отчетливое осознание этой проблемы привело к созданию Алгола—60, а позже — Паскаля, Модулы—2, Си и множества других языков программирования, имеющих более или менее развитые структуры типов данных.
Начиная с языка Симула—67, в программировании наметился новый подход, который получил название объектно—ориентированного программирования (ООП). Его руководящая идея заключается в стремлении связать данные с обрабатывающими эти данные процедурами в единое целое — объект. Характерной чертой объектов является инкапсуляция (объединение) данных и алгоритмов их обработки, в результате чего и данные, и процедуры во многом теряют самостоятельное значение. Фактически объектно—ориентированное программирование можно рассматривать как модульное программирование нового уровня, когда вместо во многом случайного, механического объединения процедур и данных акцент делается на их смысловую связь.
Какими мощными средствами располагает объектно—ориентированное программирование наглядно демонстрирует библиотека Turbo Vision, входящая в комплект поставки Турбо Паскаля.
Следует заметить, что преимущества ООП в полной мере проявляются лишь при разработке достаточно сложных программ.
- ОСНОВНЫЕ ПРИНЦИПЫ ООП
Объектно—ориентированное программирование основано на китах — трех важнейших принципах, придающих объектам новые свойства. Этими принципами являются инкапсуляция, наследование, полиморфизм.
Инкапсуляция
Инкапсуляция есть объединение в единое целое данных и алгоритмов обработки этих данных. В рамках ООП данные называются полями объекта, а алгоритмы — объектными методами.
Инкапсуляция позволяет в максимальной степени изолировать объект от внешнего окружения. Она существенно повышает надежность разрабатываемых программ, т.к. локализованные в объекте алгоритмы обмениваются с программой сравнительно небольшими объемами данных причем количество и тип этих данных обычно тщательно контролируются
Другим немаловажным следствием инкапсуляции является легкость обмена объектами, переноса их из одной программы в другую.
Наследование
Наследование есть свойство объектов порождать своих потомков. Объект — потомок автоматически наследует от родителя все поля и методы, может дополнять объекты новыми полями и заменять (перекрывать) методы родителя или дополнять их.
Принцип наследования решает проблему модификации свойств объекта и придает ООП в целом исключительную гибкость. При работе с объектами программист обычно подбирает объект, наиболее близкий по своим свойствам для решения конкретной задачи, и создает одного или нескольких потомков от него, которые “умеют” делать то, что не реализовано в родителе.
Последовательное проведение в жизнь принципа “наследуй и изменяй” хорошо согласуется с поэтапным подходом к разработке крупных программных проектов и во многом стимулирует такой подход.
Полиморфизм
Полиморфизм -это свойство родственных объектов (т.е. объектов, имеющих одного общего родителя) решать схожие по смыслу проблемы разными способами.
Для изменения метода необходимо перекрыть его в потомке, т.е. объявить в потомке одноименный метод и реализовать в нем нужные действия. В результате в объекте — родителе и объекте — потомке будут действовать два одноименных метода, имеющие разную алгоритмическую основу и, следовательно, придающие объектам разные свойства. Это и называется полиморфизмом объектов.
В Pascal полиморфизм достигается не только описанным выше механизмом наследования и перекрытия методов родителя, но и их виртуализацией (см. ниже), позволяющей родительским методам обращаться к методам потомков.
Знакомство с техникой ООП начнем на примере следующей учебной задачи. Требуется разработать программу, которая создает на экране ряд графических изображений (точки, окружность, линия, квадрат) и может перемещать эти изображения по экрану. Для перемещения изображений в программе будут использоваться клавиши управления курсором, клавиши Ноте, End, PgUp, PgDn (для перемещения по диагональным направлениям) и клавиша Tab для выбора перемещаемого объекта. Выход из программы — клавиша Esc.Техническая реализация программы потребует использования средств двух стандартных библиотек — CRT и GRAPH.
В Турбо Паскале для создания объектов используются три зарезервированных слова: object, constructor, destructor и три стандартные директивы: private, public и virtual.
Зарезервированное слово object используется для описания объекта. Описание объекта должно помещаться в разделе описания типов:
type
MyObject = object
{Поля объекта}
{Методы объекта}
end;
Если объект порождается от какого-либо родителя, имя родителя указывается в круглых скобках сразу за словом object:
type
MyDescendantObject = object(MyObject)
…
end;
Любой объект может иметь сколько угодно потомков, но только одного родителя, что позволяет создавать иерархические деревья наследования объектов.
Для нашей учебной задачи создадим объект—родитель TGraphObject, в рамках которого будут инкапсулированы поля и методы, общие для всех детальных объектов:
type
TGraphObj = object
Private {Поля объекта будут скрыты от пользователя}
X,Y: Integer; {Координаты реперной точки}
Color: Word; {Цвет фигуры}
Public {Методы объекта будут доступны пользователю}
Constructor Init(aX,aY: Integer; aColor: Word);
{Создает экземпляр объекта}
Procedure Draw(aColor: Word); Virtual;
{Вычерчивает объект заданным цветом aColor}
Procedure Show;
{Показывает объект — вычерчивает его цветом Color}
Procedure Hide;
{Прячет объект — вычерчивает его цветом фона}
Procedure MoveTo(dX,dY: Integer) ;
{Перемещает объект в точку с координатами X+dX и У+dY} end; {Конец описания объекта TGraphObj}
В дальнейшем предполагается создать объекты-потомки от TGraphObj, реализующие все специфические свойства точки, линии, окружности и прямоугольника. Каждый из этих графических объектов будет характеризоваться положением на экране (поля Х и У) и цветом (поле Color). С помощью метода Draw он будет способен отображать себя на экране, а с помощью свойств “показать себя” (метод Show) и “спрятать себя” (метод Hide) сможет перемещаться по экрану (метод MoveTo). Учитывая общность свойств графических объектов, мы объявляем абстрактный объект TGraphObj, который не связан с конкретной графической фигурой. Он объединяет в себе все общие поля и методы реальных фигур и будет служить родителем для других объектов.
Директива Private в описании объекта открывает секцию описания скрытых полей и методов. Перечисленные в этой секции элементы объекта “не видны” программисту. В нашем примере он не может произвольно менять координаты реперной точки [X,Y), т.к. это не приведет к перемещению объекта. Для изменения полей Х и Y предусмотрены входящие в состав объекта методы Init и MoveTo. Скрытые поля и методы доступны в рамках той программной единицы (программы или модуля), где описан соответствующий объект.
Директива public отменяет действие директивы private, поэтому все следующие за public элементы объекта доступны в любой программной единице. Директивы private и public могут произвольным образом чередоваться в пределах одного объекта.
Вариант объявления объекта TGraphObj без использования механизма private..public:
type
TGraphObj = object
X,Y: Integer;
Color: Word;
Constructor Init(aX,aY: Integer; aColor: Word);
Procedure Draw(aColor: Word); Virtual;
Procedure Show;
Procedure Hide;
Procedure MoveTo(dX, dY: Integer);
end;
Описания полей ничем не отличаются от описания обычных переменных. Полями могут быть любые структуры данных, в том числе и другие объекты. Используемые в нашем примере поля Х и У содержат координату реперной (характерной) точки графического объекта, а поле Color — его цвет. Реперная точка характеризует текущее положение графической фигуры на экране и, в принципе, может быть любой ее точкой.
Для описания методов в ООП используются традиционные для Паскаля процедуры и функции, а также особый вид процедур — конструкторы и деструкторы. Конструкторы предназначены для создания конкретного экземпляра объекта, ведь объект — это тип данных, т.е. “шаблон”, по которому можно создать сколько угодно рабочих экземпляров данного объектного типа (типа TGraphObj, например).
Зарезервированное слово constructor, используемое в заголовке конструктора вместо procedure, предписывает компилятору создать особый код пролога, с помощью которого настраивается так называемая таблица виртуальных методов. Если в объекте нет виртуальных методов, в нем может не быть ни одного конструктора, наоборот, если хотя бы один метод описан каквиртуальный (с последующим словом Virtual, см. метод Draw), в состав объекта должен входить хотя бы один конструктор и обращение к конструктору должно предшествовать обращению к любому виртуальному методу.
Типичное действие, реализуемое конструктором, состоит в наполнении объектных полей конкретными значениями. В нашем примере конструктор Init объекта TGraphObj получает все необходимые для полного определения экземпляра данные через параметры обращения аХ, аУ и aColor.
Процедура Draw предназначена для вычерчивания графического объекта. Эта процедура будет реализовываться в потомках объекта TGraphObj до-разному. Например, для визуализации точки следует вызвать процедуру PutPixel, для вычерчивания линии — процедуру Line и т.д. В объекте TGraphObj процедура Draw определена как виртуальная (“воображаемая”). Абстрактный объект TGraphObj не предназначен для вывода на экран, однако наличие процедуры Draw в этом объекте говорит о том, что любой потомок TGraphObj должен иметь собственный метод Draw, с помощью второго он может показать себя на экране.
При трансляции объекта, содержащего виртуальные методы, создается так называемая таблица виртуальных методов (ТВМ). В этой таблице будут храниться адреса точек входа в каждый виртуальный метод. В нашем примере ТВМ объекта TGraphObj хранит единственный элемент — адрес метода Draw.
Наличие в объекте TGraphObj виртуального метода Draw позволяет легко реализовать три других метода объекта: чтобы показать объект на экране в Методе Show, вызывается Draw с цветом aColor, равным значению поля color, а чтобы спрятать графический объект, в методе Hide вызывается Draw со значением цвета GetBkColor, т.е. с текущим цветом фона.
Рассмотрим реализацию перемещения объекта. Если .потомок TGraphObj Например, TLine) хочет переместить себя на экране, он обращается к родительскому методу MoveTo. В этом методе сначала с помощью Hide объект стирается с экрана, а затем с помощью Show показывается в другом месте.
Чтобы описать все свойства объекта, необходимо раскрыть содержимое объектных методов, т.е. описать соответствующие процедуры и функции. Описание методов производится обычным для Паскаля способом в любом месте раздела описаний, но после описания объекта. Например:
type
TGraphObj = object
…
end;
Constructor TGraphObj.Init;
begin
X := aX;
Y := aY;
Color := aColor
end;
Procedure TGraphObj.Draw;
begin
{Эта процедура в родительском объекте ничего не делает, поэтому экземпляры TGraphObj не способны отображать себя на экране. Чтобы потомки объекта TGraphObj были способны отображать себя, они должны перекрывать этот метод}
end;
Procedure TGraphObj.Show;
begin
Draw(Color)
end;
Procedure TGraphObj.Hide;
begin
Draw(GetBkColor)
end;
Procedure TGraphObj.MoveTo;
begin
Hide;
X := X+dX;
Y := Y+dY;
Show
end;
Отметим два обстоятельства. Во-первых, при описании методов имя метода дополняется спереди именем объекта, т.е. используется составное имя метода. Это необходимо по той простой причине, что в иерархий родственных объектов любой из методов может быть перекрыт в потомках. Составные имена четко указывают . принадлежность конкретной процедуры. Во-вторых, в любом объектном методе можно использовать инкапсулированные поля объекта почти так, как если бы они были определены в качестве глобальных переменных. Например, в конструкторе fGraph.Init переменные в левых частях операторов присваивания представляют собой объектные поля и не должны заново описываться в процедуре. Более того, описание
Constructor TGraphObj.Init;
var
X,Y: Integer; {Ошибка!}
Color: Word;{Ошибка!}
begin
…
end;
вызовет сообщение о двойном определении переменных X, Y и Color (в этом и состоит отличие в использовании полей от глобальных переменных: глобальные переменные можно переопределять в процедурах, в то время как объектные поля переопределять нельзя}.
Обратите внимание: абстрактный объект TGraphObj не предназначен для вывода на экран, поэтому его метод Draw ничего не делает. Однако методы Hide, Show и MoveTo “знают” формат вызова этого метода и реализуют необходимые действия, обращаясь к реальным методам Draw своих будущих потомков через соответствующие ТВМ. Это и есть полиморфизм объектов.
Создание объекта «Точка»
Создадим простейшего потомка от TGraphObj — объект TPoint, с помощью которого будет визуализироваться и перемещаться точка. Все основные действия, необходимые для этого, уже есть в объекте TGraphObj, поэтому в объекте TPoint перекрывается единственный метод — Draw.type
TPoint = object(TGraphObj)
Procedure Draw(aColor); Virtual;end;
Procedure TPoint.Draw;begin
PutPixel(X,Y,Color) {Показываем цветом Color пиксель с координатами X и Y}
end;
В новом объекте TPoint можно использовать любые методы объекта-родителя TGraphObj. Например, вызвать метод MoveTo, чтобы переместить изображение точки на новое место. В этом случае родительский метод TGraphObj. MoveTo будет обращаться к методу TPoint.Draw, чтобы спрятать и затем показать изображение точки. Такой вызов станет доступен после Обращения к конструктору Init объекта TPoint, который нужным образом настроит ТВМ объекта. Если вызвать TPoint.Draw до вызова Init, его ТВМ не будет содержать правильного адреса и программа “зависнет”.
Создание объекта «Линия»
Чтобы создать объект—линию, необходимо ввести два новых поля для хранения координат второго конца. Дополнительные поля требуется наполнить конкретными значениями, поэтому нужно перекрыть конструктор родительского объекта:
type
TLine = object (TGraphObj)
dX,dY: Integer; {Приращения координат второго конца}
Constructor Init(X1,Y1,X2,Y2: Integer; aColor: Word);
ProcedureDraw(aColor: Word); Virtual
end;
Constructor TLine.Init;
{Вызывает унаследованный конструктор TGraphObj для инициации полей X, Y и Color. Затем инициирует поля dX и dY}
begin
{Вызываем унаследованный конструктор}
Inherited Init(Xl,Yl,aColor);
{Инициируем поля dX и dY}dX := X2-X1;dY := Y2-Y1end;
Procedure Draw;
begin
SetCoior(Color) ; {Устанавливаем цвет Color}
Line(X, Y, X+dX, Y+dY) {Вычерчиваем линию}
end;
В конструкторе TLine.Init для инициации полей X, Y и Color, унаследованных от родительского объекта, вызывается унаследованный конструктор TCraph.Init, для чего используется зарезервированное слово inherited (англ.—унаследованный):
Inherited Init(Xl,Yl,aColor);
таким же успехом мы могли бы использовать и составное имя метода
TGraphOb:).Init(XI,Y1,aColor);
Для инициации полей dX и dY вычисляется расстояние в пикселах по горизонтали и вертикали от первого конца прямой, до ее второго конца. Это позволяет в методе TLine.Draw вычислить координаты второго кони по координатам первого и смещениям dX и dY. В результате простое изменение координат реперной точки Х,У в родительском i TGraph Move To перемещает всю фигуру по экрану.
Создание объекта «Круг»
Теперь нетрудно реализовать объект TCircle для создания и перемещения окружности:
type
TCircle = object(TGraphObj)
R: Integer; {Радиус}
Constructor Init(aX,aY,aR: Integer; aColor: Word);
Procedure Draw(aColor: Virtual);
end;
Constructor TCircle.Init;
begin
Inherited Init(aX,aY,aColor) ;
R := aR
end;
procedure TCircle.Draw;
begin
SetCoior(aColor); {Устанавливаем цвет Color}
Circle(X,Y,R) {Вычерчиваем окружность}
end;
Создание объекта «Прямоугольник»
В объекте TRect, с помощью которого создается и перемещается прямоугольник, учтем то обстоятельство, что для задания прямоугольника требуется указать четыре целочисленных параметра, т.е. столько же, сколько для задания линии. Поэтому объект TRect удобнее породить не от TGraphObj, а от TLine, чтобы использовать его конструктор Init:
type
TRect = object(TLine)
procedure Draw(aColor: Word);
end;
Procedure TRect.Draw;
begin
SetCoior(aColor) ;
Rectangle(X,Y,X+dX,Y+dY) {Вычерчиваем прямоугольник}
end;
Чтобы описания графических объектов не мешали созданию основной программы, оформим эти описания в отдельном модуле GraphObj:
Unit GraphObj;Interface
{Интерфейсная часть модуля содержит только объявления объектов}type
TGraphObj = object.end;
TPoint = object(TGraphOb3).end;
TLine = object (TGraphObj).end;TCircle = object(TGraphObj)end;
TRect = object(TLine)
end;
Implementation
{Исполняемая часть содержит описания веек объектных методов} Uses Graph;
Constructor TGraphObj.Init;.
end.
В интерфейсной части модуля приводятся лишь объявления объектов, подобно тому как описываются другие типы данных, объявляемые в модуле доступными для внешних программных единиц. Расшифровка объектных методов помещается в исполняемую часть implementation, как если бы это были описания обычных интерфейсных процедур и функций. При описании методов можно опускать повторное описание в заголовке параметров вызова. Если они все же повторяются, они должны в точности соответствовать ранее объявленным параметрам в описании объекта. Например, заголовок конструктора TGraphObj. Init может быть таким:
Constructor TGraphObj.Init;
или таким:
Constructor TGraphObj.Init(aX,aY: Integer; aColor: Word);
Идею инкапсуляции полей и алгоритмов можно применить не только к графическим объектам, но и ко всей программе в целом. Ничто не мешает нам создать объект—программу и “научить” его трем основным действиям: инициации (Init), выполнению основной работы (Run) и завершению (Done). На этапе инициации экран переводится в графический режим работы и создаются и отображаются графические объекты (100 экземпляров TPoint и по одному экземпляру TLine, TCircle, TRect). На этапе Run осуществляется сканирование клавиатуры и перемещение графических объектов. Наконец, на этапе Done экран переводится в текстовый режим и завершается работа всей программы.
Назовем объект—программу именем TGrapbApp и разместим его в модуле CraphApp (пока не обращайте внимание на точки, скрывающие содержательную часть модуля — позднее будет представлен его полный текст):
Unit GraphApp;
Interface type
TGraphApp = object
Procedure Init;
Procedure Run;
Destructor Done;
end;
Implementation
Procedure TGraphApp.Init;
…
end;
end.
В этом случае основная программа будет предельно простой:
Program Graph_0bjects;
Uses GraphApp;
var
App: TGraphApp;
begin
App.Init;
App. Run ;
App.Done
end.
В ней мы создаем единственный экземпляр App объекта—программы TGrahpApp и обращаемся к трем его методам.
Создание экземпляра объекта ничуть не отличается от создания экземпляра переменной любого другого типа. Просто в разделе описания переменных мы указываем имя переменной и ее тип:
var
App: TGraphApp;
Получив это указание, компилятор зарезервирует нужный объем памяти для размещения всех полей объекта TGraphApp. Чтобы обратиться к тому или иному объектному методу или полю, используется составное имя, причем первым указывается не имя объектного типа, а имя соответствующей переменной:
App.Init;
App.Run;
App.Done;
Ниже приводится возможный вариант модуля GraphApp для нашей учебной программы:
Unit GraphApp;
Interface
Uses GraphObj;
const
NPoints = 100; {Количество точек}
type
{Объект-программа}
TGraphApp = object
Points: array [1..NPoints] of TPoint; {Массив точек}
Line: TLine; {Линия}
Rect: TRect; {Прямоугольник}
Circ: TCircle; {Окружность}
ActiveObj: Integer; {Активный объект}
Procedure Init;
Procedure Run;
Procedure Done;
Procedure ShowAll;
Procedure MoveActiveObj(dX,dY: Integers;
end;
implementation
Uses Graph, CRT;
procedure TGraphApp.Init;
{Инициирует графический режим работы экрана. Создает и отображает NPoints экземпляров объекта TPoint, а также экземпляры объектов TLine, TCircle и TRect}
var
D, R, Err, k: Integer;
begin
{Инициируем графику}
D := Detect; {Режим автоматического определения типа графического адаптера)
InitGraph (D,R,’\tp\bgi’); {Инициируем графический режим. Текстовая строка должна задавать путь к каталогу с графическими драйверами}
Err := GraphResult; {Проверяем успех инициации графики}
if Err<>0 then
begin
GraphErrorMsg(Err);
Halt
end;
{Создаём точки}
for k := 1 to NPoints do
Points[k].Init(Random(GetMaxX),Random(GetMaxY),Random(15)+1);
{Создаем другие объекты}
Line.Init(GetMaxX div 3,GetMaxY div 3,2*GetMaxX div 3, 2*GetMaxY div 3, LightRed);
Circ.Init(GetMaxX div 2,GetMaxY div 2,GetMaxY div 5,White);
Rect.Init(2*GetMaxX div 5,2*GetMaxY div 5,3*GetMaxX div 5, 3*GetMaxY div 5, Yellow);
ShowAll; {Показываем все графические объекты}
ActiveObj := 1 {Первым перемещаем прямоугольник}
end; {TGraphApp.Init}
{___________________}
Procedure TGraphApp.Run ;
{Выбирает объект с помощью Tab и перемещает его по экрану}
var
Stop: Boolean; {Признак нажатия Esc}
const
D = 5; {Шаг смещения фигур}
begin
Stop := False;
{Цикл опроса клавиатуры}
repeat
case ReadKey of {Читаем код нажатой клавиши}
#27: Stop := True; {Нажата Esc}
#9: begin {Нажата Tab}
ActiveObj:= ActiveObj+1 ;
if ActiveObj>3 then ActiveObj := 3
end;
#0: case ReadKey of
#71 MoveActiveObj(-D,-D) {Влево и вверх}
#72 MoveActiveObj( 0,-D) {Вверх}
#73 MoveActiveObj( D,-D) {Вправо и вверх]
#75 MoveActiveObj(-D, 0) (Влево}
#77 MoveActiveObj( D, 0) {Вправо}
#79 MoveActiveObj(-D, D) {Влево и вниз]
#80 MoveActiveObj ( О, D) (Вниз)
#81 MoveActiveObj( D, D) (Вправо и вниз}end
end;
ShowAll;
Until Stop
end;{TGraphApp.Run}
{————————}
Destructor TGraphApp.Done;
{Закрывает графический режим}
begin
CloseGraph;
end;{TGraphApp.Done}
{————————}
Procedure TGraphApp.ShowAll;
{Показывает все графические объекты}
var
k: Integer;
begin
for k := 1 to NPoints do Points[k].Show;
Line.Show;
Rect.Show;
Circ.Show
end;
{————————}
Procedure TGraphApp.MoveActiveObj;
{Перемещает активный графический объект}
begin
case ActiveObj of
1: Rect.MoveTo(dX,dY);
2: Circ.MoveTo(dX,dY);
3: Line.MoveTo(dX,dY)
end
end;
end.
В реализации объекта TGraphApp используется деструктор Done. Следует иметь в виду, что в отличие от конструктора, осуществляющего настройку ТВМ, деструктор не связан с какими-то специфичными действиями: для компилятора слова destructor и procedure — синонимы. Введение в ООП деструкторов носит, в основном, стилистическую направленность — просто процедуру, разрушающую экземпляр объекта, принято называть деструктором. В реальной практике ООП с деструкторами обычно связывают процедуры, которые не только прекращают работу с объектом, но и освобождают выделенную для него динамическую память.
В заключении следует сказать, что формалистика ООП в рамках реализации этой технологии в Турбо Паскале предельно проста и лаконична. .Согласитесь, что введение лишь шести зарезервированных слов, из которых действительно необходимыми являются три (object, constructor и virtual), весьма небольшая плата за мощный инструмент создания современного программного обеспечения.