Solved

More interface woes (Acessing original object methods through an interface)

Posted on 2003-10-27
10
202 Views
Last Modified: 2010-04-05
Having come to the Delphi world via VB, I presumed that the following would be possible:

procedure bar( fooi: IFoo);
var
  foot : TFoo;
begin
  foot := TFoo(fooi);
  MessageBox(0,pchar(foot.str),'',1);
end;

var
  foot : TFoo;
begin
  foot := TFoo.create;
  foot.str := ('hallo');
  bar(foot);
end.

i.e. That after storing a TFoo in an IFoo that I could cast IFoo back to type TFoo. Have I done something stupid? How can I perform such a cast?
0
Comment
Question by:davelane
  • 4
  • 4
  • 2
10 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 9627250
Yep. Something stupid... But hey, we've all done stupid things in the past... ;-)

And no, a class type is not compatible with an interface. Even worse, you could have a class like this:

type TBar = class(TInterfacedObject, IFoo);

Now, the class would be TBar so what do you think would happen if you assign a TBar to a TFoo? These could be incompatible types...

An interface is nothing more than a definition of methods and where they can be found inside an object. Since multiple components can support the same interface, you're never sure that the interface is pointing to the right class. Which is why it's near-impossible to typecast an interface back to a class.

Can it be done? Sure, but the complexity is a bit much. Besides, it's a bit risky if the interface isn't a Delphi interface but created in some other application. If it is a Delphi interface then the interface is pointing to a class that is inherited from TObject. And TObject can tell you the exact class of the object. However, to get to the TObject from an interface??? I don't know exactly how to do that.
0
 

Author Comment

by:davelane
ID: 9628357
Well when I meant stupid, I meant obvious :-( In VB this is possible (because even classes have hidden interfaces). And anyway my point is that this is a reasonable thing to want to do. Imagine a unit where I define 2 objects

  I1 = interface
    function DoSomething: integer;
  end;

  T1 = class(TIntefacedObject, I1)
  private
    InternalData: string;
    function DoSomethingInternal: integer;
  public
    function DoSomething: integer;
  end;

  T2 = class(TInterfacedObject)
  public
    function DoSomethingToAT1(T1Object: I1): integer;
  end;

In function DoSomethingToAT1 I want to be able to access the private functions and data on the object but I cant do this because they are not defined on the interface.
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 9628842
Unfortunately, what you are trying is just not allowed. You use an interface to make the object more abstract and once it's more abstract you can't undo it anymore. If your interface doesn't provide access to any private methods, you just don't have any access to them. Now, with this definition:

  T2 = class(TInterfacedObject)
  public
    function DoSomethingToAT1(T1Object: T1): integer;
  end;

Notice I use T1 instead of I1. This way you will get access to the private methods. Unfortunately this doesn't allow you to send the object over through it's interface.
0
 
LVL 2

Expert Comment

by:j42
ID: 9632163
Hi davelane,

IM(H)O your should rethink about your design. If function DoSomethingToAT1(T1Object: I1) needs acess to private members of T1 then they are connected in some way. So decoupling (and as far as I understand that is what interfaces are for) is not neccessary and not possible. You could pass a T1 object to it - as Workshop_Alex said.
0
 

Author Comment

by:davelane
ID: 9632198
Thanks for the replies guys,
like I said I came from VB, where this is allowed and oft used. Have been using Delphi for 2 years now, but have only now started using Interfaces under Delphi. Like I said I (still) don't think it is an unreasonable thing to want to do. Decoupling is one of the things that interfaces facilitate, but to say they are only for decoupled object is wrong IMHO. And anyway in my case the objects are not couipled. Take this example:
2 objects with interfaces IDatabaseTable and IRow. IDatabaseTable is basically a collection of IRows. Now say I have a function IDatabaseTable.Append(IRow). It is clear that this append function will want to do things to IRow that are not on the public interface. What would be good design in this case? A hidden interface with the necessary functions: IRowInternal?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 2

Expert Comment

by:j42
ID: 9632718
Well... I have never been into VB and database programming.

> public interface
I guess in  Delphi there is nothing like a 'hidden' or private interface.

> IDatabaseTable is basically a collection of IRows
I do not like that (maybe because interfaces are slightly different in VB). I would say:
TDatabaseTable (an implementation of IDatabaseTable) is a collection of TRow s which implement IRow.

What if there is something like IDatabaseTable.Append(IRow) and you 'cast' the IRow to a TRow. I can implement another class
with an IRow interface but completely different internals. Thus Append(IRow) will crash if I pass my object to it.
As far as I understand your problem you need a certain behaviour of your rows, so why not put it in the interface? Or something like
TRow = class(TWhatEver, IRow, IForInternalManipulation);

> but to say they are only for decoupled object is wrong
I am not a native english speaker so please do not take me to literal ;-)
0
 

Author Comment

by:davelane
ID: 9632771
> TDatabaseTable (an implementation of IDatabaseTable) is a collection of TRow s which implement IRow.
You say don't take me too literally, but that is obviously what I meant. :-)

> I guess in  Delphi there is nothing like a 'hidden' or private interface.
Well by hidden I meant, not to include it in the .pas file that defines the public interfaces and / or not to include it in the tlb if and when it exists. TRow = class(TWhatEver, IRow, IForInternalManipulation); is exactly what I meant.

> What if there is something like IDatabaseTable.Append(IRow) and you 'cast' the IRow to a TRow. I can
> implement another class with an IRow interface but completely different internals. Thus Append(IRow)
> will crash if I pass my object to it.
Right, I will have to think about it though. The main reason for using interfaces in this case is to provide some kind of memory management.
0
 
LVL 2

Accepted Solution

by:
j42 earned 125 total points
ID: 9633709
> in this case is to provide some kind of memory management.
Ok, another try (beside the whole communication stuff):

IRowWrapper = interface
  function GetRow: TRow;
end;

procedure IDatabaseTable.Append(ARow: IRowWrapper);
var
  row: TRow;
begin
  row := ARow.GetRow;
  row.AccesSomeVeryPrivateAndInSomeWayHiddenDataOfRow;
  ...
end;

This way you have reference counting, access to internals and no ugly casts.
0
 

Author Comment

by:davelane
ID: 9633836
Yeah, I've already done something similar (couldn't do exactly what you said due to a problem with circular references).

IRow = interface
  function GetClassPointer: Pointer;
end;

function TRow.GetClassPointer: Pointer;
begin
  result := Self;
end;

procedure IDatabaseTable.Append(ARow: IRow);
var
  row: TRow;
begin
  row := TRow(ARow.GetClassPointer);
  row.AccesSomeVeryPrivateAndInSomeWayHiddenDataOfRow;
  ...
end;

It ain't pretty but it works. Thanks for the help.
0
 
LVL 2

Expert Comment

by:j42
ID: 9634181
I'm glad to be helpful!
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

706 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now