Delphi: Как вызвать унаследованного наследуемого предка в виртуальном методе? - PullRequest
23 голосов
/ 12 января 2011

Я переопределяю виртуальный метод и хочу вызвать , унаследованный .Но я не хочу называть непосредственного предка, я хочу назвать одного до .

TObject
   TDatabaseObject
      TADODatabaseObject <---call this guy
         TCustomer        <---skip this guy
            TVIP           <---from this guy

Я пытался разыграть self каки вызвал метод для этого, но это привело к рекурсивному переполнению стека:

procedure TVip.SetProperties(doc: IXMLDOMDocument);
begin
   TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor
   ...
end;

я попытался добавить ключевое слово inherited, но это не компилируется:

procedure TVip.SetProperties(doc: IXMLDOMDocument);
begin
   inherited TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor
   ...
end;

возможно?

Ответы [ 4 ]

28 голосов
/ 12 января 2011

Вы можете сделать это, используя взломать получение статического адреса виртуального метода:

type
  TBase = class
    procedure Foo; virtual;
  end;

  TAnsestor = class(TBase)
    procedure Foo; override;
  end;

  TChild = class(TAnsestor)
    procedure Foo; override;
    procedure BaseFoo;
  end;

procedure TBase.Foo;
begin
  ShowMessage('TBase');
end;

procedure TAnsestor.Foo;
begin
  ShowMessage('TAnsestor');
end;

procedure TChild.Foo;
begin
  ShowMessage('TChild');
end;

type
  TFoo = procedure of object;

procedure TChild.BaseFoo;
var
  Proc: TFoo;

begin
  TMethod(Proc).Code := @TBase.Foo; // Static address
  TMethod(Proc).Data := Self;
  Proc();
end;

procedure TForm4.Button1Click(Sender: TObject);
var
  Obj: TChild;
  Proc: TFoo;

begin
  Obj:= TChild.Create;
  Obj.BaseFoo;
// or else
  TMethod(Proc).Code := @TBase.Foo; // Static address
  TMethod(Proc).Data := Obj;
  Proc();

  Obj.Free;
end;
17 голосов
/ 12 января 2011

Вы не можете обычным языком, так как это может нарушить объектно-ориентированные аспекты языка.

Вы можете поиграться с указателями и умными приведениями, чтобы сделать это, но даже прежде чем начать отвечатьчто: это действительно то, что вы хотите?

Как уже упоминали другие: ваша потребность звучит как серьезный «дизайнерский запах» (который похож на кодовый запах , но более серьезен.

Редактировать:

Переход по путанице указателя может спасти вашу работу в краткосрочной перспективе и стоить вам недель работы в долгосрочной перспективе.
Это делает для некоторыххорошее прочтение на этом: Решения для восходящего потока, расходы на нижестоящий поток .

9 голосов
/ 12 января 2011

Я помню, что несколько лет назад мне приходилось делать что-то подобное, обходя некоторые ограничения дизайна иерархии VCL.

Так что, похоже, что-то вроде этого:

type
  TGrandParent = class(TObject)
  public
    procedure Show;virtual;
  end;

  TParent = class(TGrandParent)
  public
    procedure Show;override;
  end;

  THackParent = class(TGrandParent)
  private
    procedure CallInheritedShow;
  end;

  TMyObject = class(TParent)
  public
    procedure Show;override;
  end;


{ TGrandParent }

procedure TGrandParent.Show;
begin
  MessageDlg('I''m the grandparent', mtInformation, [mbOk], 0);
end;

{ TParent }

procedure TParent.Show;
begin
  inherited;
  MessageDlg('I''m the parent', mtInformation, [mbOk], 0);
end;

{ THackParent }

procedure THackParent.CallInheritedShow;
begin
  inherited Show;
end;

{ TVIP }

procedure TMyObject.Show;
begin
  THackParent(Self).CallInheritedShow;
end;

procedure TForm6.Button6Click(Sender: TObject);
var
  VIP: TMyObject;
begin
  VIP:=TMyObject.Create;
  try
    VIP.Show;
  finally
    VIP.Free;
  end;
end;

Не ужинать- элегантный, но все же решение :) 1006 *

3 голосов
/ 12 января 2011

Если вы действительно хотите это сделать, вы должны извлечь в отдельный защищенный метод ту часть иерархии наследования, на которую вы хотите иметь возможность ссылаться напрямую.Это позволит вам вызывать его из любой точки мира, не отправляя виртуальные методы, побеждающие вас.

Однако, как я уже говорил, кажется, что с дизайном вашего класса что-то не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...