Одноимённые методы
Ещё раз посмотрим на различные способы замены методов базового класса-предка на одноимённый метод в классе-потомке.
Статическое замещение методов
В классе потомке объявляется метод с тем же именем и набором формальных параметров.
Метод класса потомка перекрывается одноимённым методом в классе-предке. Из класса-потомка обратиться к методу класса-предка невозможно.
Например:
type
TMyClass1=class
procedure pr1;
end;
TMyClass2=class(TMyClass1)
procedure pr1;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyClass1.pr1;
begin
showMessage(‘TMyClass1.pr1’);
end;
procedure TMyClass2.pr1;
begin
showMessage(‘TMyClass2.pr1’);
end;
procedure TForm1.Button1Click(Sender: TObject);
var vPr1:TMyClass1;
begin
vPr1:=TMyClass1.Create;
vPr1.pr1;
end;
procedure TForm1.Button2Click(Sender: TObject);
var vPr2:TMyClass2;
begin
vPr2:=TMyClass2.Create;
vPr2.pr1;
end;
end.
Никаким образом из переменной vPr2 вызвать процедуру, принадлежащую классу TmyClass1, невозможно.
Динамическое замещение методов
Такой способ позволяет обратиться как к методу родителя, так и к методу класса-последователя.
type
TMyClass1=class
procedure pr1; virtual;
end;
TMyClass2=class(TMyClass1)
procedure pr1; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyClass1.pr1;
begin
showMessage(‘TMyClass1.pr1’);
end;
procedure TMyClass2.pr1;
begin
showMessage(‘TMyClass2.pr1’);
end;
procedure TForm1.Button1Click(Sender: TObject);
var vPr1:TMyClass1;
begin
vPr1:=TMyClass1.Create;
vPr1.pr1;
FreeAndNil(vPr1);
vPr1:=TMyClass2.Create;
vPr1.pr1;
FreeAndNil(vPr1);
end;
end.
При клике по кнопке сначала происходит обращение к методу класса-предка, а затем к его дочернему классу. И это оказывается возможным через переменную базового класса!
Таким образом сохраняется доступ как к методу класса-предка, так и к одноимённому методу класса-последователя.
Одноимённые методы.
Существует ещё один способ использовать одноимённые методы.
Хотя имя всех методов одно и то же, но у каждого должен быть свой уникальный набор параметров. Причём методы могут располагаться в одном и том же классе.
Перекрываемые методы должны иметь ключевое слово overload.
Кроме того, чтобы каждый раз не выводилось сообщение о том, что метод перекрывается, необходимо использовать сочетание ключевых слов reintroduce; overload; (именно в такой последовательности).
type
TMyClass1=class
procedure pr1;
end;
TMyClass2=class(TMyClass1)
procedure pr1(s:string); reintroduce; overload;
procedure pr1(s1,s2:string); reintroduce; overload;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyClass1.pr1;
begin
showMessage(‘TMyClass1.pr1’);
end;
procedure TMyClass2.pr1(s:string);
begin
showMessage(‘TMyClass2.pr1(s:string) ‘+s);
end;
procedure TMyClass2.pr1(s1,s2:string);
begin
showMessage(‘TMyClass2.pr1(s1,s2:string) ‘+s1+’ ‘+s2);
end;
procedure TForm1.Button1Click(Sender: TObject);
var vPr1:TMyClass1;
begin
vPr1:=TMyClass1.Create;
vPr1.pr1;
FreeAndNil(vPr1);
end;
procedure TForm1.Button2Click(Sender: TObject);
var vPr2:TMyClass2;
begin
vPr2:=TMyClass2.Create;
vPr2.pr1;
vPr2.pr1(‘***’);
FreeAndNil(vPr2);
end;
procedure TForm1.Button3Click(Sender: TObject);
var vPr2:TMyClass2;
begin
vPr2:=TMyClass2.Create;
vPr2.pr1(‘***’,’###’);
FreeAndNil(vPr2);
end;
end.
Динамическое перекрытие.
Динамическое перекрытие методов по синтаксису мало отличается от виртуальных методов. Вместо ключевого слова virtual указывается ключевое слово dynamic. Механизмы обращения к методам в обоих случаях идентичны.
Разница заключается в том, виртуальная таблица класса хранит адреса входов в методы, помеченные как override во всех предках, а также в потомке, в потомке потомка и так далее.
То есть объём таблицы может быть достаточно большим, зато выбор метода осуществляется за один заход в таблицу. Это обеспечивает высокую скорость нахождения метода.
Встречая ключевое слово dynamic компилятор создаёт динамическую таблицу и присваивает каждому динамическому методу свой индекс, уникальный в цепочке иерархии данного класса.
Встретив вызов динамического метода через переменную, тип которой задан через какой-либо класс, происходит поиск в динамической таблице этого класса.
Если метода с требуемым индексом в таблице не окажется, то последовательно просматривается вся цепочка предков и происходит просмотр их динамических таблиц, пока нужный метод не будет обнаружен.
* * *