Иллюстрированный самоучитель по Turbo Pascal

Полиформные коллекции

В объектах TCircle (окружность) и TRectangle (прямоугольник) инкапсулированы новые поля, поэтому перекрываются также и методы Init:

Constructor TCircle.Init;
{Создает окружность случайного радиуса в случайном месте}
begin
TGraphObject.Init; {Получаем координаты центра}
R: = Random(GetMaxY div 2) {Получаем радиус}
end;
Procedure TCircle.Draw;
{Вычерчивает окружность}
begin
Circle(X, Y, R)
end;
Constructor TRectangle.init;
{Создает случайный прямоугольник}
begin
TGraphObject.Init;{Верхний левый угол}
W: = Random(GetMaxX div 2) {Ширина}
H: = Random(GetMaxY div 2) {Высота}
end;
Procedure TRectangle.Draw;
{Вычерчивает прямоугольник}
begin
Rectangle(X, Y, X+W, Y+H)
end;

После того как определены нужные объекты, не составляет особого труда поместить эти объекты в коллекцию и вывести их на экран. Например, для вывода всех элементов коллекции можно использовать такую процедуру:

Procedure DrawAll (C: PCollection);
{Выводит все элементы полиморфной коллекции}
Procedure DrawItem(p: PGraphObject); far;
begin
p.Draw {Это и есть полиморфизм в действии!}
end;
begin
С.ForEach(@DrawItem)
end;

Как видим, в процедуре DrawItem полиморфизм используется дважды: во-первых, метод ForEach обращается к ней, передавая в качестве параметра обращения нетипизированный указатель на элемент коллекции; это позволяет трактовать параметр как указатель на любой объект, в том числе и на TGraphObject. Во-вторых, в процедуре используется обращение к виртуальному методу объекта-родителя Draw: поскольку этот метод перекрывается во всех потомках, каждый из них будет использовать свой метод Draw для вывода на экран.

Сформируем программу, поместив в нее вместо, точек уже рассмотренные фрагменты:

Uses Objects,Graph,CRT;
type
…..
Constructor TGraphObject.Init;
…..
Procedure TGraphObject.Draw;
…..
Constructor TPoint.Init;
…..
Procedure TPoint.Draw;
…..
Constructor TCircle.Init;
…..
Procedure TCircle.Draw;
…..
Constructor TRectangle.Init;
…..
Procedure TRectangle.Draw;
…..
Procedure DrawAll(C: PCollection);
…..
var
a, r, k: Integer;
List: PCollection;
p: Pointer;
begin .a: = 0;
{Инициируем графический режим работы экрана:}
InitGraph(a, r, '\TP\BGI');
r: = GraphResult; if r < > 0 then
WriteLn(GraphErrorMsg(r)) {Ошибка инициации}
else
begin
{Создаем коллекцию:}
List: = New(PCollection, Init (20.5));
{Наполняем ее 20 элементами:}
for k: = 1 to 20 do
begin
case k mod 3 of
0: p: = New(PPoint, Init);
1: p: = New(PCircle, Init);
2: p: = New(PRectangle, Init)
end;
if p < > NIL then List.Insert(p)
end;
DrawAll(List); {Выводим на экран все элементы}
While not KeyPressed do;{Ждем нажатия на любую клавишу}
CloseGraph {Возвращаемся в текстовый режим}
end
end.

В этой программе предполагается, что драйвер графического экрана расположен в каталоге \TF\BGI на текущем диске. Если это не так, следует указать маршрут поиска этого драйвера в качестве параметра обращения к процедуре InitGraph. Кроме того, каталог, содержащий стандартную графическую библиотеку Graph, должен быть указан опцией Options/Directories/Unit directories, если, разумеется, библиотека не содержится в текущем каталоге.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.