самое можно сказать и о квадрате. Что это значит с точки зрения программирования? То, что класс TCircle, наследник класса TShape можно использовать везде, где можно использовать класс TShape. Более того, все переменные и методы класса TShape (кроме private) будут также доступны в классе TCircle.
Не буду сильно углубляться в теорию, всё–таки я предпочитаю объяснять на примерах, поэтому сразу перейдём к тому как изменится наша функция с попмощью этого нехитрого преобразования:
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;
На самом деле тоже не очень красиво. Приходится для каждого примитива делать проверку, поддерживает–ли он нужный нам тип (оператор is) и осуществлять приведение типов (оператор as). Операторы is и as предназначены для работы только с объектами и не работают с простыми типами. Подробнее о них можно прочитать в документации.
Чтобы оценить мощь наследования нам остался всего один шаг. В класс TShape добавим строку «function HitTest(X, Y: Integer): Boolean; virtual; abstract;”, а в классы TCircle и TRectangle добавим после аналогичных строчек ключевое слово override:
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;
Что это означает? Мы как бы говорим, что класс TShape в принципе может проверить, попали в него координаты мыши или нет, но конкретная реализация зависит от того, какой именно примитив используется. То есть абстрактно функциональность есть, но её реализация должна быть переопределена в классах потомках.
Нашу многострадальную функцию теперь можно переписать так:
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
Result:= Shapes[I].HitTest(X, Y);
if Result then
Exit;
end;
end;
При этом, в случаю кругов, в реальности будет вызываться функция TCircle. HitTest, а в случае прямоугольников — TRectangle. HitTest.
Понятно, что в случае с одной абстрактной функцией выигрышь не совсем очевиден, но ведь можно расширить базовый класс, добавив в него функции:
TShape. Move(dx, dy: Integer); virtual; abstract;
для перемещения примитива,
TShape. Rotate(x, y: Integer; angel: Double); virtual; abstract;
для поворота вокруг точки,
TShape. Flip(Line: TLine); virtual; abstract;
для зеркального отображения вокруг прямой.
Реализация данных методов уникальна для каждого из классов наследников, однако сама функциональность применима ко всем графическим примитивам.
Последние комментарии
11 часов 55 минут назад
12 часов 14 минут назад
12 часов 22 минут назад
12 часов 24 минут назад
12 часов 26 минут назад
12 часов 44 минут назад