Link to home
Start Free TrialLog in
Avatar of karouri
karouri

asked on

How to use interfaces?

Hi, all
I would like to create some components that all implement an interface, say IMyInterface, and then in a form check for the components that implement the interface. In other words, if:

TClass1 = class(TGraphicControl,IMyInterface)
  ...
end;

TClass1 = class(TGraphicControl,IMyInterface)
  ...
end;

then in my form I would like to do

for i:=0 to ComponentCount-1 do
begin
  if Components[i] is IMyInterface then
  begin
    //....
  end;
end;

Is that possible, or is there any other way to check if a component implements an interface and to typecast it?
Avatar of Jacco
Jacco
Flag of Netherlands image

Something like this should work:

var
  lMyIntf: IMyInterface;
begin
  for i:=0 to ComponentCount-1 do
  begin
    if Supports(Components[i], IMyInterface, lMyIntf) then
    begin
      lMyIntf.DoInterfaceThing(...);
    end;
  end;
end;

Regards Jacco
listening
Avatar of TOndrej
TOndrej

Jacco: I believe you need to set IMyIntf := nil; in each iteration of the loop, to decrease reference count
Avatar of karouri

ASKER

I thinl you are right, Jacco. But I think that this needs a QueryInterface definition on TClass1 and TClass2, and I wasn't able to do it.
As for the reference count, it happens that TClass1 & TClass2 are components, so I will define _AddRef and _Release to skip memory management..
k
ASKER CERTIFIED SOLUTION
Avatar of TOndrej
TOndrej

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of karouri

ASKER

Excellent, TOndrej. That does exactly what I want. And thanks everyone.
btw, is it as simple to do it without delegation?
Hi karouri,

Thanks for the points.

TGraphicControl inherits IUnknown support from TComponent which bypasses reference counting (except for ActiveX-ed controls), so you could simply (re)implement the interface in every control, e.g.

class
  TMyControl1 = class(TGraphicControl, ISomething)
  protected
    procedure DoSomething; virtual; // make it virtual if you want to give descendants a possibility to override
  end;

In fact, that's possibly a better option for you, depending on what you want to do...

If the interface implementation is going to be very similar for each control (and there will be many controls) then it might be better to have a separate base implementor class and use delegation (each control could delegate to a descendant but most funcionality would already be implemented in the base class)

If it doesn't sound like worth all the work or every control will implement the interface differently (so having a base implementor class doesn't make sense), then simply implement your interface in every control, as shown above.

HTH
Avatar of karouri

ASKER

Thanks TOndrej, I have done it without delegation. But as I tested it here, mentioning IUnknown in the interface is a must, like:
  TMyControl2 = class(TGraphicControl, IUnknown, ISomething)
  private
    FSomething: TSomething;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DoSomeThing;
  end;
If you omit IUnknown then the Supports function will work but will not find TMyControl2. That was one of my errors in the first place.
Thanks again
k