Link to home
Start Free TrialLog in
Avatar of hec08036
hec08036

asked on

How can i cast interface to class?

Hello,

does anyone know how to cast an object that implements interfaces to its real class type?
For example, if i have the
following class

IFoo = interface
[some GUID]
  procedure Bar;
end;

TFoo = class(TInterfacedObject, IFoo)
  procedure Bar;
end;

i can cast TFoo to IFoo with As:

Foo := TFoo.Create
(Foo As IFoo).Bar

But if i say

(Foo as TFoo).Bar

i get the compiler-error:

Operation not applicable to this operand type.

I need this for using a class with TList.IndexOf. If i have for
example

IBar = interface
...

IFoo = interface
  function GetBar: IBar;
  procedure SetBar(Bar: IBar);
  property Bar: IBar read GetBar write SetBar;
end;


TFoo = class(TInterfacedObject, IFoo)
...


and there is a method of TFoo, where i have to search for a bar, and
i use the interface -- it fails

Foo := TFoo.Create;

Somelist.IndexOf(Foo.Bar)  // doesnt find anything

So i would need the real class type of Bar. My first attempt was to
do an unchecked cast (which the compiler gladly accepts):

...
var
SomeBar: TBar

...
SomeBar := TBar(Foo.Bar);
Somelist.IndexOf(SomeBar);

but this fails.

What to do?

Chris

 
Avatar of Epsylon
Epsylon

How did you define the variable Foo? I get no compiler errors when I do this:

var Foo: TObject;

(Foo as TFoo).Bar;
Hi Chis,

the unchecked type cast as you did above is the way you would usually "convert" an interface to a class (if the class implements this interface, of course). The reason why this works is that the class is just a pointer as well as the interface and both point to the same memory. The other way around with the "as" operator could also be done using an unchecked type cast but with the "as" operator there is an implicit reference count increment and a "type" checking involved (read: whether the class actually implements the interface).

Another point is that properties are not allowed in interfaces. So I don't know why the compiler accepts your Bar/SetBar/GetBar construct.

You have not shown the declaration of TBar but I assume it's:

TBar = class(TInterfacedObject, IBar)
  :
end;

In this case you should be able to cast an IBar to a TBar without problems. YOu can check this with a private variable of TBar. Create an instance, pass it around as IBar, cast it back to TBar and see if the private variable contains a value you have set before.

If all fails you can try another approach. Store the interfaces in the list instead of the classes. Actually it's the same pointer as I already wrote but the compiler might handle this situation different.

Ciao, Mike
Mike: A correction. An interface CAN define a property, but it can't store anything. Note that that both set and get accessors are defined - the implementor of the interface stores the property value and provides access to it through those accessor methods inthe interface.

Chris: Calling Bar in Foo is done by Foo.Bar as you have already tried - there is no casting required to call it. The fact that it fails suggests your Bar method is wrong rather than the interface mechanism :-)

Cheers,

Raymond.
ASKER CERTIFIED SOLUTION
Avatar of Madshi
Madshi

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
Hi Madshi,

Bar is just a method in the interface, it doesn't represent the actual interface, so it is meaningless to attempt to get the object instance just given bar alone.

I also don't see the point of the GetSelfAsObject method. Isn't self defined in the implemented methods from the interface?

Maybe I'm missing something... :-)

Cheers,

Raymond.
:-)

Well, the Bar property gives us an IBar instance. This IBar instance is implemented by an unknown object - let's say a TIBar object. Now Chris has stored all TIBar objects in a TList (not the IBar instances!!). How can he find out which list index belongs to that IBar instance? Only by getting the object pointer of the object that implements the IBar instance that we get from the Bar method. Right?
Of course "self" is defined in the methods of that interface (that's how my GetSelfAsTObject method works).
But he needs to know the implementing object from OUTSIDE the methods!!
Tell me: If we have this:

var aBar : IBar;
    aBarObj : TIBar;
begin
  aBar := OtherInterface.GetBar;
  aBarObj := ????

How do you get the aBarObj that belongs to aBar? That's Chris' question. And the only answer I know is to add a method to the IBar interface. Then you can do this:

  aBarObj := aBar.GetSelfAsTObject as TIBar;

Regards, Madshi.
DOH! I was looking at the first code sample where Bar is just a procedure... I see where GetSelfAsObject comes into it...

BTW, isn't the Bar property superfluous (ie: You can use GetInterface to do the same..)

Cheers,

Raymond.

PS: There are a couple of good articles in the last month on interfaces on community.borland.com...
>> BTW, isn't the Bar property superfluous (ie: You can use GetInterface to do the same..)

No, you can't. GetInterface only gives you the interfaces that are directly implemented in the class. Then TFoo had to look like this:

type
  TFoo = class (TInterfacedObject, IFoo, IBar)

THEN you could use GetInterface to get an IBar instance.

Regards, Madshi.
Hi guys,

wow, it's been quite busy here since yesterday :-) Madshi, thank you for the correction, I'm obviously wrong (although I was so sure about the same pointer thing, where did I get this idea from ....?). Now I finally understand your GetSelfAsTObject :-)

Ciao, Mike
=:-D
Avatar of hec08036

ASKER

Thanks a lot! Now it works.

Best Regards

Chris