Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

How can i cast interface to class?

Posted on 2000-04-11
11
Medium Priority
?
1,018 Views
Last Modified: 2012-06-21
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

 
0
Comment
Question by:hec08036
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 2
  • +2
11 Comments
 
LVL 13

Expert Comment

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

var Foo: TObject;

(Foo as TFoo).Bar;
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2703814
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
0
 
LVL 12

Expert Comment

by:rwilson032697
ID: 2706055
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.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 20

Accepted Solution

by:
Madshi earned 400 total points
ID: 2706668
Hi friends,

Raymond is right, an interface CAN have properties, no problem there.

But Ray, Chris wants to get the TBar object pointer from the IBar interface pointer he got from "Foo.Bar". THAT'S the problem.

Mike, I'm sorry, but it's not allowed to simply typecast interfaces to objects. That's a strictly NO NO - otherwise you'll get exceptions. Try this code:

type
  ITest = interface
  end;
  TITest = class (TInterfacedObject, ITest)
  end;

var tit : TITest;
    it  : ITest;
initialization
  tit := TITest.Create;
  it := tit;
  if pointer(tit) = pointer(it) then
    beep;

The pointers are NOT identical!!

Chris, I'm solving this problem usually by adding a "GetSelfAsTObject" method to my base interface, that does nothing but this:

type
  IMyBaseInterface = interface
    function GetSelfAsTObject : TObject;
  end;
  TIMyBaseInterface = class (TInterfacedObject, IMyBaseInterface)
    function GetSelfAsTObject : TObject;
  end;

function TIMyBaseInterface.GetSelfAsTObject : TObject
begin
  result := self;
end;

Regards, Madshi.
0
 
LVL 12

Expert Comment

by:rwilson032697
ID: 2706690
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.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 2706724
:-)

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.
0
 
LVL 12

Expert Comment

by:rwilson032697
ID: 2706745
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...
0
 
LVL 20

Expert Comment

by:Madshi
ID: 2706752
>> 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.
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2706840
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
0
 
LVL 20

Expert Comment

by:Madshi
ID: 2706861
=:-D
0
 

Author Comment

by:hec08036
ID: 2707599
Thanks a lot! Now it works.

Best Regards

Chris
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
Suggested Courses

604 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question