Порядок вызова перекрытых методов

Материал из GedeminWiki
Перейти к: навигация, поиск

Порядок вызова перекрытых методов в случае множественного наследования рассмотрим на таком примере. Пусть в платформе определен ClassA -- пользовательский справочник. От него наследуется ClassB. Для этих классов перекрыт метод DoBeforeOpen c вызовом Inherited. У нас на руках экземпляр класса ClassB, который мы пытаемся открыть (Open), в процессе чего происходит вызов метода DoBeforeOpen. Тогда последовательность выполнения программного кода будет выглядеть следующим образом:


polymorphism.png


1 -- ClassA и ClassB -- это исключительно порождения платформы о которых Делфи ничего не известно. Для системы объект имеет тип TgdcAttrUserDefined.

2 -- Поскольку для TgdcAttrUserDefined нет метода DoBeforeOpen, через VMT попадаем на метод родителя -- TgdcBase.DoBeforeOpen.

3 -- Тело метода начинается с кода, который отвечает за вызов перекрытых методов в платформе. На вставке ниже, строки, начинающиеся с комментария:

procedure TgdcBase.DoBeforeOpen;
  {@UNFOLD MACRO INH_ORIG_PARAMS(VAR)}
  {M}VAR
  {M}  Params, LResult: Variant;
  {M}  tmpStrings: TStackStrings;
  {END MACRO}
begin
  {@UNFOLD MACRO INH_ORIG_WITHOUTPARAM('TGDCBASE', 'DOBEFOREOPEN', KEYDOBEFOREOPEN)}
  {M}  try
  {M}    if (not FDataTransfer) and Assigned(gdcBaseMethodControl) then
  {M}    begin
  {M}      SetFirstMethodAssoc('TGDCBASE', KEYDOBEFOREOPEN);
  {M}      tmpStrings := TStackStrings(ClassMethodAssoc.IntByKey[KEYDOBEFOREOPEN]);
  {M}      if (tmpStrings = nil) or (tmpStrings.IndexOf('TGDCBASE') = -1) then
  {M}      begin
  {M}        Params := VarArrayOf([GetGdcInterface(Self)]);
  {M}        if gdcBaseMethodControl.ExecuteMethodNew(ClassMethodAssoc, Self, 'TGDCBASE',
  {M}          'DOBEFOREOPEN', KEYDOBEFOREOPEN, Params, LResult) then exit;
  {M}      end else
  {M}        if tmpStrings.LastClass.gdClassName <> 'TGDCBASE' then
  {M}        begin
  {M}          Inherited;
  {M}          Exit;
  {M}        end;
  {M}    end;
  {END MACRO}
 
  if (not CanView) and (not IBLogin.IsUserAdmin) then
  begin
    if SubType > '' then
      raise EgdcUserHaventRights.CreateFmt(strHaventRights,
        [strView, ClassName, SubType, GetDisplayName(SubType)])
    else
      raise EgdcUserHaventRights.CreateFmt(strHaventRightsShort,
        [strView, ClassName])
  end;
 
  if not FSQLInitialized then
    InitSQL;
 
  if HasSubSet('ByID') and (FID > -1) then
    ParamByName(GetKeyField(SubType)).AsInteger := FID
  else if HasSubSet('ByName') and (FObjectName > '') then
    ParamByName(GetListField(SubType)).AsString := FObjectName;
 
  inherited DoBeforeOpen;
 
  {@UNFOLD MACRO INH_ORIG_FINALLY('TGDCBASE', 'DOBEFOREOPEN', KEYDOBEFOREOPEN)}
  {M}  finally
  {M}    if (not FDataTransfer) and Assigned(gdcBaseMethodControl) then
  {M}      ClearMacrosStack2('TGDCBASE', 'DOBEFOREOPEN', KEYDOBEFOREOPEN);
  {M}  end;
  {END MACRO}
end;

Именно здесь вступает в силу Подтип нашего объекта и система начинает понимать, что мы имеем дело с экземпляром TgdcAttrUserDefinedClassB, а не TgdcAttrUserDefined. В базе данных отыскивается скрипт-функция перекрытого метода, загружается в скрипт-контрол и запускается на выполнение.

4 -- По магическому слову Inherited мы снова оказываемся в движке платформы. Для класса TgdcAttrUserDefinedClassB будет найден родитель -- TgdcAttrUserDefinedClassA. Для него загружена скрипт-функция перекрытого метода и запущена на выполнение.

5 -- Снова вызов Inherited из скрипт-функции. На этот раз родитель -- делфовский класс TgdcAttrUserDefined. Для него нет метода DoBeforeOpen и мы возвращаемся в TgdcBase.DoBeforeOpen. Служебный код, отвечающий за связь Делфи с VBScript, закончился. Начинается логика метода DoBeforeOpen.

6, 7 -- По вызову inherited перейдем на уровень родителя -- TCustomIBDataSet.DoBeforeOpen. По завершении -- вернемся обратно.

8 -- Собственно, логика метода DoBeforeOpen закончилась. Снова служебный код, который сращивает статичный, однажды откомпилированный код Делфи и динамичный, интерпретируемый код из VBScript. Возращаемся в место вызова -- TgdcAttrUserDefinedClassA.DoBeforeOpen, сразу после слова Inherited.

9 -- Когда выполнение скрипт-функции перекрытого метода закончится, движок платформы вернет нас к прерванному TgdcAttrUserDefinedClassB.DoBeforeOpen.

A, B, C -- Скрипты закончились. Завершаем метод TgdcBase.DoBeforeOpen. Затем, минуя несуществующий TgdcAttrUserDefined.DoBeforeOpen, возвращаемся к продолжению программы.

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты