Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi: How to call inherited inherited ancestor on a virtual method?

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?

like image 981
Ian Boyd Avatar asked Jan 11 '11 21:01

Ian Boyd


4 Answers

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;
like image 58
kludg Avatar answered Nov 10 '22 02:11

kludg


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.

like image 18
Jeroen Wiert Pluimers Avatar answered Nov 10 '22 02:11

Jeroen Wiert Pluimers


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 :)

like image 9
Maksee Avatar answered Nov 10 '22 02:11

Maksee


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.

like image 3
David Heffernan Avatar answered Nov 10 '22 02:11

David Heffernan