Объекты в турбо ПаскалеРефераты >> Программирование и компьютеры >> Объекты в турбо Паскале
Наличие в объекте TGraphObj виртуального метода Draw позволяет легко реализовать три других метода объекта: чтобы показать объект на экране в методе Show, вызывается Draw с цветом aColor, равным значению поля Color, а чтобы спрятать графический объект, в методе Hide вызывается Draw со значением цвета GetBkColor, т.е. с текущим цветом фона.
Рассмотрим реализацию перемещения объекта. Если потомок TGraphObj (например, TLine) хочет переместить себя на экране, он обращается к родительскому методу MoveTo. В этом методе сначала с помощью Hide объект стирается с экрана, а затем с помощью Show показываетя в другом месте. Для реализации своих действий и Hide, и Show обращаются к виртуальному методу Draw. Поскольку вызов MoveTo происходит в рамках объекта TLine, используется ТВМ этого объекта и вызывается его метод Draw, вычерчивающий прямую. Если бы перемещалась окружность, ТВМ содержала бы адрес метода Draw объекта TСircle и визуализация-стирание объекта осуществлялась бы с помощью этого метода.
Чтобы описать все свойства объекта, необходимо раскрыть содержимое объектных методов, т.е. описать соответствующие процедуры и функуии. Описание методов производится обычным для Паскаля способом в любом месте раздела описаний, но после описания объекта. Например:
type
TGraphObj = object
end;
Сonstructor TGraphObj.Init;
begin
X:= aX;
Y:= aY;
Color:= aColor
еnd;
Рrocedure 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;
end;
Отмечу два обстоятельства. Во-первых, при описании методов имя метода дополняется спереди именем объекта, т.е. используется составное имя метода. Это необходимо по той простой причине, что в иерархии родственных объектов любой из методов может быть перекрыт в потомках. Составные имена чётко указывают принадлежность конкретной процедуры. Во-вторых, в любом объектном методе можно использовать инкапсулированные поля объекта почти так, как ели бы они были определены в качестве глобальных переменных. Например, в конструкторе TGraph.Init переменные в левых частях операторов присваивания представляют собой объектные поля и не должны заново описываться в процедуре. Более тонко, описание Constructor TGraph.Init:
var
X,Y: Integer; {ошибка!}
Color: Word; {ошибка!}
begin
.end;
вызовет сообщение о двойном определении переменных X, Y, Color (в этом и состоит отличие в использовании полей от глобальных переменных: глобальные переменные можно переопределять в процедурах, в то время как объектные поля переопределять нельзя).
Стоит обратить внимание на то, что абстрактный объект TGraphObj не предназначен для выводя на экран, поэтому его метод Draw ничего не делает. Однако методы Hide, Show, MoveTo “знают” формат вызова этого метода и реализуют необходимые действия, обращаясь к реальным методам Draw своих будущих потомков через соответствующие ТВМ. Это и есть полтморфизм объектов.
Создадим простейшего потомка от Tgraphobj — объект TРoint, с помощью которого будет визуализироваться и перемещаться точка. Все основные действия, необходимые для этого, уже есть в объекте TGraphObj, поэтому в объекте TPoint перекрывается единственный метод — Draw:
type
TPoint = object (TGraphObj)
Procedure Draw (aColor); Virtual;
end;
Procedure TPoint.Draw;
begin
PutPixel (X,Y,Color) {показываем цветом Color пиксель с координатами X и Y}
end;
В новом объекте TРoint можно использовать любые методы объекта-родителя TGraphObj. Например, вызвать метод MoveTo, чтобы переместить изображение точки на новое место. В этом случае родительский метод TGraphObj.MoveTo будет обращаться к методу TPoint.Draw, чтобы спрятать и затем показать изображение
точки. Такой вызов станет доступен после обращения к конструктору Init объекта TРoint, который нужным образом настроит ТВМ объекта. Если вызвать TPoint.Draw до вызова Init, его ТВМ не будет содержать правильного адреса и программа “зависнет”.
Чтобы создат объект-линию, необходимо ввести два новых поля для хранения координат другого конца.
Дополнительные поля требуется наполнить конкретными значениями, поэтому нужно перекрыть конструктор родительского объекта:
type
TLine = object (TGraphObj)
dX, dY: Integer; {Приращение координат второго конца}
Constructor Init (X1, Y1, X2, Y2: Integer; aColor: Word); Virtual;
end;
Constructor TLine.Init;
{Вызывает унаследованный конструктор TGraphObj для инициации полей X, Y, Color. Затем инициирует поля dX, dY}
begin
{Вызываем унаследованный конструктор}
Inherited Init (X1, Y1, aColor);
{Инициируем поля dX, dY}
dX:= X2-X1;
dY:= Y2-Y1
end;
Procedure Draw;
begin
SetColor (Color); {Устанавливаем цвет Color}
Line (X, Y, X+dX, Y+dY) {Вычерчиваем линию}
end;
В конструкторе TLine.Init для инициации полей X, Y, Color, унаследованных от родмтельского объекта, вызывается унаследованный конструктор TGraph.Init, для чего используется зарезервированное слово inherited (англ. — унаследованный):
Inherited Init (X1, Y1, aColor);
C таким же успехом мы могли бы использовать и составное имя метода:
TGraphObj.Init (X1, Y1, aColor);
Для инициации полей dX и dY вычисляется расстояние в пикселах по горизонтали и вертикали от первого конца прямой до её второго конца. Это позволяет в методе TLine.Draw вычислить координаты второго конца по координатам первого и смещениям dX, dY. В результате простое изменение координат реперной точки X,Y в родительском методе TGraph.MoveTo перемещает всю фигуру по экрану.
Теперь нетрудно реализовать объект TСircle для создания и перемещения окружности:
type
TCircle = object (TGraphObj)
R: Integer;
Constructor Init (aX, aY, aR: Integer; aColor: Word);
Procedure Draw (aColor: Virtual);
еnd;
Constructor TCircle.Init;
begin
Inherited Init (aX, aY, aColor);
R:= aR
end;
Procedure TCircle.Draw;
begin
SetColor (aColor); {устанавливает цвет Color}
Circle (X, Y, R) {вычерчивает окружность}
end;
В объекте Trect, с помощью которого создаётся и перемещается прямоугольник, учтём то обстоятельство, что для задания прямоугольника требуется указать четыре целочисленных параметря, т.е. столько же, сколько для задания линии. Поэтому объект TRect удобнее породить не от TGraphObj, а от TLine, чтобы использовать его конструктор Init:
tуpe
TRect = object (TLine)
Procedure Draw (aColor: Word);
end;
Procedure TRect.Draw;
begin
SetColor (aColor);
Rectangle (X, Y, X+dX, Y+dY) {вычерчиваем прямоугольник}