Это была реализация классов, а тут реализация базовой функции HitTest, которая должна проверить все наши объекты:
var
Circles: array of TCircle;
Rectangles: array of TRectangle;
function HitTest(X, Y: Integer): Boolean;
var
I: Integer;
begin
Result:= False;
for I:= 0 to Length(Rectangles) — 1 do
begin
Result:= Rectangles[I].HitTest(X, Y);
if Result then
Exit;
end;
for I:= 0 to Length(Circles) — 1 do
begin
Result:= Circles[I].HitTest(X, Y);
if Result then
Exit;
end;
end;
Не слишком компактно получилось. А теперь представим, что разных типов примитивов у нас десятки и даже сотни. Получается для каждого нужен свой массив, и свой цикл для функции
В чём тут смысл? Вместо нескольких массивов для каждого графического примитива отдельно, мы заводим класс, который описывает графический примитив, назовём его, например, TShape. Далее мы хотим хранить все наши примитивы, независимо от их типа в массиве «Shapes: array of TShape». Но так просто у нас это не получится, компилятор ругнётся, что типы не совместимы.
Для того, чтобы мы смогли положить наши прямоугольники и круги в массив
type
TShape = class(TObject)
end;
TCircle = class(TShape)
public
…..
end;
TRectangle = class(TShape)
public
…..
end;
Теперь наш круг одновременно и круг и графический примитив, равно как и в действительности. То же самое можно сказать и о квадрате. Что это значит с точки зрения программирования? То, что класс
Не буду сильно углубляться в теорию, всё–таки я предпочитаю объяснять на примерах, поэтому сразу перейдём к тому как изменится наша функция с попмощью этого нехитрого преобразования:
var
Shapes: array of TShape;
function HitTest(X, Y: Integer): Boolean;
var
I: Integer;
begin
Result:= False;
for I:= 0 to Length(Shapes) — 1 do
begin
if Shapes[I] is TCircle then
Result:= (Shapes[I] as TCircle).HitTest(X, Y)
else if Shapes[I] is TRectangle then
Result:= (Shapes[I] as TRectangle).HitTest(X, Y)
if Result then
Exit;
end;
end;
На самом деле тоже не очень красиво. Приходится для каждого примитива делать проверку, поддерживает–ли он нужный нам тип (оператор
Чтобы оценить мощь наследования нам остался всего один шаг. В класс
type
TShape = class(TObject)
public
function HitTest(X, Y: Integer): Boolean; virtual; abstract;
end;
TCircle = class(TShape)
public
…..
function HitTest(X, Y: Integer): Boolean; override;
end;
TRectangle = class(TShape)
public
…..
function HitTest(X, Y: Integer): Boolean; override;
end;
Что это означает? Мы как бы говорим, что класс
Нашу многострадальную функцию теперь можно переписать так:
var
Shapes: array of TShape;
function HitTest(X, Y: Integer): Boolean;
var
I: Integer;
begin
Result:= False;
for I:= 0 to Length(Shapes) — 1 do
begin