Jean-Louis Senegas February 2016

Create generic class or interface with self typed parameters in children classes

I'd like to create a class or interface that I could subclass, always using current class instances as methods parameters...

Here is an example to explain my problem:

 type IArithmeticObject = interface(IInterface)
   procedure assign(ao : IArithmeticObject);
   procedure add(ao : IArithmeticObject);
   procedure remove(ao : IArithmeticObject);
   procedure multiply(ao : IArithmeticObject);
   procedure divide(ao : IArithmeticObject);
 end;

the interface IArithmeticObject whould be the starting point, referencing basic arithmetic operations and child classes could be declared as

 type TInteger = class(TInterfacedObject, IArithmeticObject)
   procedure assign(ao : TInteger);
   procedure add(ao : TInteger);
   procedure remove(ao : TInteger);
   procedure multiply(ao : TInteger);
   procedure divide(ao : TInteger);
 end;

with parameter type for ao being TInteger and not IArithmeticObject.

Another idea would be to use a self referencing generic type like:

  AMathObject = class;

  AMathObject<T : AMathObject, constructor> = class
    procedure assign(ao : T);virtual;abstract;
    procedure add(ao : T);virtual;abstract;
    procedure remove(ao : T);virtual;abstract;
    procedure multiply(ao : T);overload;virtual;abstract;
    procedure divide(ao : T);virtual;abstract;
  end;

but I could not figure out the right syntax...

Does anyone have any ideas about this possibility (or impossibility)?

Answers


fantaghirocco February 2016

If I undestand it correctly, you may want to derive your class from a generic interface.

type
  IArithmeticObject<T> = interface
    procedure assign(ao: IArithmeticObject<T>);
    procedure add(ao: IArithmeticObject<T>);
    procedure remove(ao: IArithmeticObject<T>);
    procedure multiply(ao: IArithmeticObject<T>);
    procedure divide(ao: IArithmeticObject<T>);
  end;

  TInteger = class (TInterfacedObject, IArithmeticObject<TInteger>)
    procedure assign(ao: IArithmeticObject<TInteger>);
    procedure add(ao: IArithmeticObject<TInteger>);
    procedure remove(ao: IArithmeticObject<TInteger>);
    procedure multiply(ao: IArithmeticObject<TInteger>);
    procedure divide(ao: IArithmeticObject<TInteger>);
  end;

Answer edited according to the Stefan Glienke's comment: now the methods of the class accept parameters declared either as objects or interfaces.

var
  ao: IArithmeticObject<TInteger>;
begin
  ao := TInteger.Create;
  ao.multiply(ao);
end.

Post Status

Asked in February 2016
Viewed 3,193 times
Voted 10
Answered 1 times

Search




Leave an answer