我正在覆盖虚拟方法,我想调用继承。但我不想打电话给立即祖先,我想在之前打电话给。
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;
可能的?
答案 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!