Шаг 77.
Решение задачи. Создание объектов-потомков

    На этом шаге мы рассмотрим создание дочерних объектов.

    Абстрактный объект 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.
Текст модуля можно взять здесь.

    На следующем шаге мы начнем разбирать использование объектов.


Предыдущий шаг Содержание Следующий шаг