На этом шаге мы рассмотрим создание дочерних объектов.
Абстрактный объект TGraphObj не предназначен для вывода на экран, поэтому его метод Draw ничего не делает. Однако методы Hide, Show и MoveTo "знают" формат вызова этого метода и реализуют необходимые действия, обращаясь к реальным методам Draw своих будущих потомков через соответствующие ТВМ. Это и есть полиморфизм объектов.
Создадим простейшего потомка от TGraphObj - объект TPoint, с помощью
которого будет визуализироваться и перемещаться точка. Все основные действия, необходимые
для этого, уже есть в объекте TGraphObj, поэтому в объекте TPoint перекрывается
единственный метод - Draw:
Type
TPoint = Object (TGraphObj)
Procedure Draw (Color) ; 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 ) ; Procedure Draw (aColor: Word) ; Virtual ; End; Constructor TLine.Init ; {Вызывает унаследованный конструктор TGraphObj} {для инициации полей X, Y и Color. Затем инициирует поля dX и dY} Begin Inherited Init (X1, Y1, aColor) ; {Вызываем унаследованный конструктор} dX: = X2-X1; {Инициируем поля dX и dY} dY: = Y2-Y1; End; Procedure TLineDraw; Begin SetColor (Color) ; {Устанавливаем цвет Color} Line (X, Y, X+dX, Y+dY); {Вычерчиваем линию} End;
В конструкторе TLine.Init для инициации полей X, Y и Color,
унаследованных от родительского объекта, вызывается унаследованный конструктор
TGraphObj.Init, для чего используется зарезервированное слово Inherited
(унаследованный):
Inherited Init (X1, Y1, aColor);
С таким же успехом мы могли бы использовать и составное имя метода:
TGraphObj.Init (X1, Y1, aColor) ;
Для инициации полей dX и dY вычисляется расстояние в пикселях по горизонтали и вертикали от первого конца прямой до ее второго конца. Это позволяет в методе TLine.Draw вычислить координаты второго конца по координатам первого и смещениям dX и dY. В результате простое изменение координат реперной точки X, Y в родительском методе TGraphObj.MoveTo перемещает всю фигуру по экрану.
Теперь нетрудно реализовать объект TCircle для создания и перемещения окружности:
Type TCircle = Object (TGraphObj) R:Integer; {Радиус} Constructor Init (aX, aY, aR: Integer; aColor: Word ) ; Procedure Draw (aColor:Word); Virtual ; End; 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:
Type TRect = Object (TLine); Procedure Draw (aColor: Word); End; Procedure TRect.Draw ; Begin SetColor (aColor) ; Rectangle (X, Y, X+dX, Y+dY); {Вычерчиваем прямоугольник} End;
Чтобы описания графических объектов не мешали созданию основной программы, оформим эти описания в отдельном модуле GraphObj:
Unit GraphObj; Interface Type TGraphObj = Object Private X,Y:Integer; Color:Word; Public Constructor Init (aX,aY:Integer;aColor:Word); Procedure Draw (aColor:Word);Virtual; Procedure Show; Procedure Hide; Procedure MoveTo(dX,dY: Integer); End; TPoint = Object (TGraphObj) Procedure Draw (aColor:Word);Virtual; End; TLine = Object (TGraphObj) dX,dY: Integer; Constructor Init (X1,Y1,X2,Y2: Integer; aColor: Word); Procedure Draw (aColor: Word); Virtual; End; TRect = Object (TLine) Procedure Draw (aColor: Word);Virtual; End; TCircle = Object (TGraphObj) R: Integer; Constructor Init (aX,aY,aR: Integer; aColor: Word); Procedure Draw (aColor: Word);Virtual; End; Implementation Uses Graph; Constructor TGraphObj.Init; Begin X:=aX; Y:=aY; Color:=aColor; End; Procedure TGraphObj.Draw; Begin 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; Procedure TPoint.Draw; Begin PutPixel(X,Y,Color); End; Constructor TLine.Init; Begin Inherited Init(X1,Y1,aColor); dX:=X2-X1; dY:=Y2-Y1; End; Procedure TLine.Draw; Begin SetColor(aColor); Line(X,Y,X+dX,Y+dY); End; Procedure TRect.Draw; Begin SetColor(aColor); Rectangle(X,Y,X+dX,Y+dY); End; Constructor TCircle.Init; Begin Inherited Init(aX,aY,aColor); R:=aR; End; Procedure TCircle.Draw; Begin SetColor(aColor); Circle(X,Y,R); End; End.
На следующем шаге мы начнем разбирать использование объектов.