Redshift
Redshift

Reputation: 25

Delphi object casting

I have a main class and several inherited classes that implement a method with the same name, like this:

MainClass = class(TImage)
  //main class methods...
end;

MyClass1 = class(MainClass)
  procedure DoSomething;
end;

MyClass2 = class(MainClass)
  procedure DoSomething;
end;

MyClass3 = class(MainClass)
  procedure DoSomething;
end;

I also have a TList containing pointers to object instances (of several classes). If I want to call the right DoSomething procedure for each class, do I use the following?

if TList[i] is MyClass1 then
  MyClass1(TList[i]).DoSomething
else if TList[i] is MyClass2 then
  MyClass2(TList[i]).DoSomething
else if TList[i] is MyClass3 then
  MyClass3(TList[i]).DoSomething

Is there some casting method that allows me to do this in a few lines of code?

Upvotes: 2

Views: 2861

Answers (2)

Kornel Kisielewicz
Kornel Kisielewicz

Reputation: 57525

Yes, virtual polymorphism :)

MainClass = class(TImage)
  procedure DoSomething; virtual;
end;

MyClass1 = class(MainClass)
  procedure DoSomething; override;
end;

MyClass2 = class(MainClass)
  procedure DoSomething; override;
end;

MyClass3 = class(MainClass)
  procedure DoSomething; override;
end;

And then just:

if TList[i] is MainClass then
  MainClass(TList[i]).DoSomething

If you don't want to do an empty MainClass.DoSomething procedure, you can also mark it virtual; abstract;.

Upvotes: 10

Brad Stowers
Brad Stowers

Reputation: 326

The virtual inheritance answer is the best for the situation you described where the classes descend from a common base class, but if you have a situation where there is not a common base class between your classes and you need this behavior, you can use interfaces instead to achieve the same result:

  IMainInterface = interface
    ['{0E0624C7-85F5-40AF-ADAC-73B7D79C264E}']
    procedure DoSomething;
  end;

  MyClass = class(TInterfacedObject, IMainInterface)
    procedure DoSomething;
    destructor Destroy; override;
  end;

  MyClass2 = class(TInterfacedObject, IMainInterface)
    procedure DoSomething;
  end;

  MyClass3 = class(TInterfacedObject, IMainInterface)
    procedure DoSomething;
  end;

and then using it would look something like this:

var
  i: integer;
  list: TInterfaceList;
  main: IMainInterface;
begin
  list := TInterfaceList.Create;

  list.Add(MyClass.create);
  list.Add(MyClass2.Create);
  list.Add(MyClass3.Create);

  for i := 0 to 2 do
    if Supports(list[i], IMainInterface, main) then
      main.DoSomething;

  list.Free;

Upvotes: 4

Related Questions