Delphi:如何在虚方法上调用继承的继承祖先?

时间:2011-01-11 21:14:19

标签: delphi inheritance

我正在覆盖虚拟方法,我想调用继承。但我不想打电话给立即祖先,我想在之前打电话给

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;

可能的?

5 个答案:

答案 0 :(得分:27)

你可以通过获取虚拟方法的静态地址来实现它:

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;

答案 1 :(得分:16)

你不能用常规的语言方式,因为这会破坏语言的面向对象方面。

你可以用指针和聪明的演员来做这件事,但在开始回答之前:这真的是你想要的吗?

正如其他人所说:你的需要听起来像一个严肃的“设计气味”(类似于code smell,但更严重。

修改

沿着指针摆弄道路可能会在短期内节省你的工作,并且长期花费你数周的工作量。
这样可以很好地阅读:Upstream decisions, downstream costs

答案 2 :(得分:8)

我记得几年前我必须做这样的事情来解决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;

不是优雅但仍然是解决方案:)

答案 3 :(得分:3)

如果您确实想要这样做,那么您应该将您希望能够直接引用的继承层次结构的一部分提取到单独的受保护方法中。这将允许您从任何地方调用它,而无需虚拟方法调度击败您。

但是,正如我所评论的那样,你的班级设计似乎有些不妥。

答案 4 :(得分:0)

使用 TGrandAncestor(self).DoSomething();

States <- States %>% 
  mutate(WAGE_BUCKET=case_when(ID <= c(1,12) ~ '1',
                               ID <= c(13,24) ~ '2',
                               ID <= c(25,37) ~ '3',
                               ID <= c(38,50) ~ '4',
                              TRUE ~ 'NA'))
View(States) #It is not grouping the states in the way I want/I am still getting some NA values but unsure why!