Question

I have a TList of an interface

IImage = interface
// another methods...
  procedure Draw;
end;

that draw different stuff in a Canvas.

and a parent class

TCustomImage = class(TInterfacedObject, IImage)
   procedure Draw; virtual; abstract;
end;

and a couple of child classes

TSomeShape = class(TCustomImage, IImage)
   procedure Draw(aCanvas:TCanvas); reintroduce; overload;
end;

TSomeAnotherShape = class(TCustomImage, IImage)
   procedure Draw(aCanvas:TCanvas); reintroduce; overload;
end;

I would like to code as below:

var
  list : TList<IImage>;
  shape : IImage;
begin
  try
    list := TList<IImage>.Create;

    list.Add(TSomeShape.Create(atSomePosition));
    list.Add(TSomeAnotherShape.Create(atSomePosition));

    // or better :)
    for shape in list do
      shape.Draw(Canvas); // TSomeShape and TSomeAnotherShape respectively.

  finally
    FreeAndNil(list);
  end;  
end;

UPD
I want to use the list.Items[I].draw() with the correct classes (TSomeShape or TSomeAnotherShape). But now, I see that it is impossible with this IImage interface. I had a method Draw(Canvas:TCanvas) in the IImage but thought that it is acceptably to reintroduce method in classes.

Thanks, I`ll work on my code. :)

Was it helpful?

Solution

The problem is that your interface is defined incorrectly. Your concrete classes implement methods with this signature:

procedure Draw(Canvas: TCanvas);

But your interface defines a method with this signature:

procedure Draw;

You do need your interface and the concrete implementations to match. You'll want code like this:

type
  IImage = interface
    procedure Draw(Canvas: TCanvas);
  end;

  TCustomImage = class(TInterfacedObject, IImage)
    procedure Draw(Canvas: TCanvas); virtual; abstract;
  end;

  TSomeShape = class(TCustomImage)
    procedure Draw(Canvas: TCanvas); override;
  end;

  TSomeOtherShape = class(TCustomImage)
    procedure Draw(Canvas: TCanvas); override;
  end;

Now everything matches and your code should compile fine, and maybe even do what you want it to.


As an aside, your try is in the wrong place. You must place it after you instantiate the object. Write

obj := TSomeClass.Create;
try
  // use obj
finally
  obj.Free;
end;

As you have it in your code, an exception in the constructor will lead to the finally block running and attempting to call free on an uninitialized reference.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top