0

I want to create an Interfaced object that supports an Interface from somewhere else + my own functions. So, how to stack/aggregate/enhance the Interface? I guess its possible, but I cant find a snippet or demo specific for my inheritance experiment.

This solution is not quite what I want:

TImplement = Class(TInterfacedObject, IOne, ITwo)
private
  FOne: IOne;
public
  property One: IOne read FOne implements IOne;
  property Two: ITwo read FTwo implements ITwo;
end;

Current usage:

(MyInterface as IOne).Something;
(MyInterface as ITwo).SomethingElse;

Desired usage:

MyInterface.Something;
MyInterface.SomethingElse;

I tried inheriting the Interface:

ITogether = Interface(IOne)
  procedure SomeThingElse;
end:

TImplement = Class(TInterfacedObject, ITogether)
// or Class(TInterfacedObject, ITogether, IOne) => Both result in missing Implementation message on compile ... 
private
  FOne: IOne;
  function SomeThingElse;
public
  property One: IOne read FOne implements IOne;
end;

This combination says something like:

E2291 Implementation of Method x From Interface IOne missing.

Is it possible to combine the Interface in a way so that the "cast free" calls are possible?

Edit: Rob Lambden´s answer is for me the missing Information. Uwe Raabes Answer is the Correct implementation. (And probably the only one possible) So uwe wins the answer and i can only upvote Robs answer.

2 Answers2

3

You can implement the IOne methods and forward them to the FOne interface.

type
  IOne = interface
    ['{19F785C0-5D2E-479F-BB2C-88A00BA4C812}']
    procedure Something;
  end;

  ITogether = interface(IOne)
    ['{B8B7F690-DC98-41AB-A6D9-29F70330EDA5}']
    procedure SomethingElse;
  end;

type
  TTogether = class(TInterfacedObject, ITogether)
  private
    FOne: IOne;
  protected
    property One: IOne read FOne;
  public
    constructor Create(AOne: IOne);
    procedure SomethingElse;
    procedure Something;
  end;

constructor TTogether.Create(AOne: IOne);
begin
  inherited Create;
  FOne := AOne;
end;

procedure TTogether.Something;
begin
  One.Something;
end;

procedure TTogether.SomethingElse;
begin
  { Do something else }
end;

AFAIK, there is no language construct like implements that does that for you when the implementor is an interface property.

Update: In case you have several cases where you need to extend the IOne interface, you can write a wrapper class that in turn makes a good candidate for the implements keyword.

type
  TOneWrapper = class
  private
    FOne: IOne;
  protected
    property One: IOne read FOne;
  public
    constructor Create(AOne: IOne);
    procedure Something;
  end;

type
  TTogether = class(TInterfacedObject, ITogether)
  private
    FOne: TOneWrapper;
  protected
    property One: TOneWrapper read FOne implements ITogether;
  public
    constructor Create(AOne: IOne);
    destructor Destroy; override;
    procedure SomethingElse;
  end;

constructor TTogether.Create(AOne: IOne);
begin
  inherited Create;
  FOne := TOneWrapper.Create(AOne);
end;

destructor TTogether.Destroy;
begin
  FOne.Free;
  inherited Destroy;
end;

procedure TTogether.SomethingElse;
begin
  { Do something else }
end;

constructor TOneWrapper.Create(AOne: IOne);
begin
  inherited Create;
  FOne := AOne;
end;

procedure TOneWrapper.Something;
begin
  One.Something;
end;
Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
  • Yes, ist´s one Possible solution. My "Foreign" Interface has around 80 Elements. And i dont want to have the Maintenance on me. – Quelltextknecht Sep 23 '21 at 09:21
  • Maintenance can be reduced to changes in method signatures and new or deleted methods. Both are found by compiling. – Uwe Raabe Sep 23 '21 at 11:03
  • I have added a way to reduce coding when several extensions of the base interface are needed. – Uwe Raabe Sep 23 '21 at 11:13
  • @UweRaabe "Interface properties" are a bit of a misnomer IMHO. If you declare a property as part of an interface, and then create an object which implements that interface, the property is not part of the object unless it is redeclared (so you can access the property through an Interface reference but not through the object reference). The accessor methods are there, but not the property. Seems very odd to me ... – Rob Lambden Sep 23 '21 at 12:54
  • @RobLambden, with "Interface properties" I am referring here to properties that are of some "interface" type. – Uwe Raabe Sep 23 '21 at 13:44
  • @UweRaabe Thanks for responding to my comment, but I'm not sure it actually addresses the observation. I think about the implementation of an interface in terms of inheritance (because I have a c++ background) which is probably why it seems odd that when you declare an object class as inheriting an interface it only inherits the methods, not the properties of some "interface" type that it inherits from. The properties can be accessed by an interface reference, but not by the object reference, unless you also declare the property in the class. – Rob Lambden Sep 24 '21 at 10:06
1

Your question appears to be about two things. Firstly it's about calling the methods without having to cast.

Just use the object reference and you can do exactly that.

  MyObject:=TImplements.Create;
  MyObject.Something;
  MyObject.SomethingElse;

Secondly it's about implementing an interface without having to re-implement the functions.

Delphi Interfaces, by their definition, cannot include implementations. (The methods have to be abstract, or in C++ terms they are 'pure virtual').

This means that you cannot do a multiple-inheritance type implementation like you can with C++. Any object implementing an interface must implement all of the implementing functions ... or ...

You can delegate an interface to a property as in your example, and if you do that you can still call the methods without casting if you use the object reference.

Rob Lambden
  • 2,175
  • 6
  • 15
  • Ok, Thank you. This Answers my Question. Summary: "Without reimplemention of the methods delphi cant call the Functions from an Interface. From a Object reference its Possible." This answers my Question and ends my Experiment. I Just wanted to substitute the interface in already existing Code. But I see: I have to typecast my new additional functionality where i need them. – Quelltextknecht Sep 23 '21 at 09:25
  • I note you have said that this answers your question ... but you have not selected it as the answer. If I can improve the answer please advise so that I can better help someone else. – Rob Lambden Sep 23 '21 at 12:52
  • Yes i know ... your answer to why i cant Inherit the interfaces without reimplementing was the missing Information to end my Search for my desired solution. If i could i would combine both answers to one ... and give both of you the Answer. (I tried, didnt work) – Quelltextknecht Sep 23 '21 at 17:34