I'm overriding a virtual method, and I want to call inherited. But I don't want to call the immediate ancestor, I want to call the one before.
TObject
TDatabaseObject
TADODatabaseObject <---call this guy
TCustomer <---skip this guy
TVIP <---from this guy
I tried casting myself
as the ancestor, and call the method on that, but it led to recursive stack overflow:
procedure TVip.SetProperties(doc: IXMLDOMDocument);
begin
TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor
...
end;
i tried adding the inherited
keyword, but that doesn't compile:
procedure TVip.SetProperties(doc: IXMLDOMDocument);
begin
inherited TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor
...
end;
Possible?
You can do it using a hack of obtaining static address of virtual method:
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;
You can't in a regular language way, as this would break the object oriented aspects of the language.
You can fiddle around with pointers and clever casts to do this, but before even starting to answer that: is this really what you want?
As others mentioned: your need sounds like a serious "design smell" (which is similar to code smell, but more severe.
Edit:
Going down the pointer fiddling road might save you work in the short term, and cost you weeks of work in the long term.
This makes for some good reading on that: Upstream decisions, downstream costs.
I remember I had to do something like this some years ago working around some design limitation of VCL hierarchy.
So it seems it was something like this:
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;
Not supper-elegant but still a solution :)
If you really want to do this then you should extract into a separate protected method the part of the inheritance hierarchy that you want to be able to reference directly. This will allow you to call it from anywhere without virtual method dispatch defeating you.
However, as I have commented, it seems like there is something awry with your class design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With