Delphi Unit local variables - how to make each instance unique? - delphi

In the unit below I have a variable declared in the IMPLEMENTATION section - local to the unit. I also have a procedure, declared in the TYPE section which takes an argument and assigns that argument to the local variable in question. Each instance of this TFrame gets passed a unique variable via passMeTheVar.
What I want it to do is for each instance of the frame to keep its own version of that variable, different from the others, and use that to define how it operates. What seems to be happening, however, is that all instances are using the same value, even if I explicitly pass each instance a different variable.
ie:
Unit FlexibleUnit;
interface
uses
//the uses stuff
type
TFlexibleUnit=class(TFrame)
//declarations including
procedure makeThisInstanceX(passMeTheVar:integer);
private
//
public
//
end;
implementation
uses //the uses
var myLocalVar;
procedure makeThisInstanceX(passMeTheVar:integer);
begin
myLocalVar:=passMeTheVar;
end;
//other procedures using myLocalVar
//etc to the
end;
Now somewhere in another Form I've dropped this Frame onto the Design pane, sometimes two of these frames on one Form, and have it declared in the proper places, etc. Each is unique in that :
ThisFlexibleUnit : TFlexibleUnit;
ThatFlexibleUnit : TFlexibleUnit;
and when I do a:
ThisFlexibleUnit.makeThisInstanceX(var1); //want to behave in way "var1"
ThatFlexibleUnit.makeThisInstanceX(var2); //want to behave in way "var2"
it seems that they both share the same variable "myLocalVar".
Am I doing this wrong, in principle? If this is the correct method then it's a matter of debugging what I have (which is too huge to post) but if this is not correct in principle then is there a way to do what I am suggesting?
EDIT:
Ok, so the lesson learned here is that the class definition is just that. Many classes can go in one unit and all instances of all classes in the Type section share the implementation section of the unit.

myLocalVar is a global variable, but only visible within the unit.
A local variable would be in a procedure/function, like
procedure makeThisInstanceX(passMeTheVar: integer);
var
myLocalVar: Integer;
begin
myLocalVar := passMeTheVar;
end;
if you want an instance variable, that is each frame has its own copy, put it in the class:
type
TFlexibleUnit = class(TFrame)
procedure makeThisInstanceX(passMeTheVar:integer);
private
myLocalVar: Integer;
...
end;

You are calling the makeThisInstanceX method as a class (static) method rather than creating an instance of the class and calling it as an object method. Take a look at this reference:
http://oreilly.com/catalog/delphi/chapter/ch02.html

frame / unit / class / control
I applaud your heroic attempt to better the code. However, judging by your questions and comments I regret to inform you that your understanding is very limited.
A frame is not a unit which is not a class. A frame is a class but not every class is a frame. A frame is a control but not every control is a frame. Units have interface and implementation (and initialization and finalization) sections. Classes have private and public (and protected and published) parts.
I did not put the last paragraph in to try to teach but to allow you to gauge your understanding level. A Delphi developer ought to have no problem with the paragraph. I'm not trying to make you feel bad or to show off - just trying to help. Perhaps Stack Overflow is not the right tool for you at this time.
As somebody just learning Delphi for the first time, I might be confused by some of the seemingly redundant features. But the product has a long history and each addition made sense at the time it was added. It was also easier to learn when you only had to learn it a piece at a time.

Related

Class doesn't work when defined as a global variable in delphi

I created a simple class to explain my problem:
ttest =class
private
val:boolean;
published
function get:boolean;
end;
...
function ttest.get: boolean;
begin
val:=not val;
result:=val;
end;
Now if I declare a local ttest variable and call my_var.get; then everything works, but if I declare it as a global variable then it can't access the val field anymore, it shows an error message which says "Access violation...".
I read some articles about classes in Delphi but still can't find my mistake.
You've neglected to instantiate the class.
Global class-reference variables are initialized to nil, whereas local variables are not initialized at all. The local variable has a value determined by whatever happened to be on the stack at the time you called your function, and your program is interpreting that value as though it were a TTest reference even though it's really not. Your program then reads the value at that memory address to get the value that would represent the val field.
The only reason your code appears to work with a non-global variable is luck. Whether it's good luck or bad is another matter. (Good luck, since your code appeared to work, and working code is always nice. Bad luck, since you'd have been alerted to your mistake earlier if your code had crashed.)
Instantiate a class before you use references to it.
x := TTest.Create;
Now you can access fields, methods, and properties of the object via the x variable.
You should have gotten a compiler warning when you attempted to use a local variable without assigning a value to it first. Although they're just warnings, and your program will still run, never ignore a warning or even a hint. When the compiler bothers to complain about something, it's usually right.
In Delphi object variables are always pointers. Before you can use the variable you need to initialize it with a reference to an object. The most common way to do that is to create a new object of the particular class.
procedure Foo;
var
Obj: TObject;
begin
Obj := TObject.Create;
try
// Do stuff with Obj
finally
Obj.Free;
end;
end;
In this case Obj starts out as an uninitialized pointer (it will point to random memory). It is only after we assign the newly created TObject that Obj is a valid object reference.
In Delphi there is no automatic garbage collection for objects, so you always need to call free on them when you are done using them. If you declare a global or local object variable, you can initialize it the special initialization section of the unit and free the object in the finalization section.
unit myunit;
interface
var
Obj: TObject;
implementation
initialization
Obj := TObject.Create;
finalization
Obj.Free;
end.
Variables declared in the interface section are globally visible, variables declared in the implementation section are only visible inside the unit. It should be noted that declaring a global object variable means that any unit can overwrite the variable with a reference to a new object without freeing the existing object first. This would cause a memory leak as again there is no automatic garbage collection.
A delphi class is basically just a description, not the object itself. You describe the properties and methods the final object should have. And the missing piece of the puzzle is that you havent really told Delphi to create an object from your class.
This is done by calling the constructor:
mMyInstance:=TTest.Create;
The constructor takes the class description and builds an object instance for you in memory. It returns a pointer to the object which you must store in a variable (myInstance in the above example) of the same type.
Reading your question, I suspect you want to create an object that is "always there", a bit like the printer object. This is easy to do, but just like the printer object - you must include that unit before you can access the object. I think Anders E. Andersen above has shown how most people would initialize an object from a unit centric point of view.
If you want the object to be reachable from another unit, say your mainform or any other unit, first add "myunit" to the uses list. Then to make it visible you add a function, like this:
function test:ttest;
Begin
result:=obj;
end;
And remember to add "function test:TTest" to the interface section of the unit. Then you can use the object from another unit as such:
myUnit.test.get;
But be warned! This is pretty old school programming, and you run the risk of your unit being released (which calls finalization and thus destroys your object) before the other units are done with it. Thus you risk calling a function in an object which no longer exists in memory - causing a spectacular access violation when your program closes.
If you want to learn Delphi properly, head over to Delphi Basics and read up on the basic principles. It takes a while to learn a new language but you will soon get the hang of it.
Good luck!

Internal (memory) representation of TProc and references at all

Does anyone here know how Delphi represents a reference to procedure?
for example
var
proc: TProc;
...
proc = procedure begin beep end;
What do we got in "proc"?
I know that for "method variable" the memory representation is 4 bytes for the "procedure address" followed by 4 bytes for the "object address", but for "reference to procedure" is somewhat different and I cannot quite figure it out.
The reason I want this is because I have some legacy code that I want to make it work with references.
Does anyone know something about it?
Method references are implemented as a COM-style interface with a single method called Invoke, which has the same signature as the method reference.
So TProc looks like this:
type
TProc = interface(IInterface) // so inherits QI, AddRef, Release
procedure Invoke;
end;
It's a valid question to ask, as Delphi has interoperability with the C++ product. By using a pre-existing reference-counted type and idiom (COM lifetime rules), interop with C++ at the method reference level is possible.
Anonymous methods generate a hidden class which implements an interface isomorphic to the method reference interface, i.e. exactly the same shape, but not with the same symbolic identity. The hidden class doesn't implement the method reference interface directly because it may need to implement the interface multiple times (a single block may contain multiple anonymous methods all assigned to locations of the same method reference type).

Delphi class references... aka metaclasses... when to use them

I've read the official documentation and I understand what class references are but I fail to see when and why they are best solution compared to alternatives.
The example cited in the documentation is TCollection which can be instantiated with any descendant of TCollectionItem. The justification for using a class reference is that it allows you to invoke class methods whose type is unknown at compile time (I assume this is the compile time of TCollection). I'm just not seeing how using TCollectionItemClass as an argument is superior to using TCollectionItem. TCollection would still be able to hold any descendant of TCollectionItem and still be able to invoke any method declared in TCollectionItem. Wouldn't it?
Compare this with a generic collection. TObjectList appears to offer much the same functionality as TCollection with the added benefit of type safety. You are freed from the requirement to inherit from TCollectionItem in order to store your object type and you can make a collection as type specific as you want. And if you need to access item's members from within the collection you can use generic constraints. Other than the fact that class references are available to programmers prior to Delphi 2009 is there any other compelling reason to use them over generic containers?
The other example given in the documentation is passing a class reference to a function that acts as an object factory. In this case a factory for creating objects of type TControl. Its not really apparent but I'm assuming the TControl factory is invoking the constructor of the descendant type passed to it rather than the constructor of TControl. If this is the case then I'm starting to see at least some reason for using class references.
So I guess what I'm really trying to understand is when and where class references are most appropriate and what do they buy a developer?
MetaClasses and "class procedures"
MetaClasses are all about "class procedures". Starting with a basic class:
type
TAlgorithm = class
public
class procedure DoSomething;virtual;
end;
Because DoSomething is a class procedure we can call it without an instance of TAlgorithm (it behaves like any other global procedure). We can do this:
TAlgorithm.DoSomething; // this is perfectly valid and doesn't require an instance of TAlgorithm
Once we've got this setup we might create some alternative algorithms, all sharing some bits and pieces of the base algorithm. Like this:
type
TAlgorithm = class
protected
class procedure DoSomethingThatAllDescendentsNeedToDo;
public
class procedure DoSomething;virtual;
end;
TAlgorithmA = class(TAlgorithm)
public
class procedure DoSomething;override;
end;
TAlgorithmB = class(TAlgorithm)
public
class procedure DoSomething;override;
end;
We've now got one base class and two descendent classes. The following code is perfectly valid because we declared the methods as "class" methods:
TAlgorithm.DoSomething;
TAlgorithmA.DoSomething;
TAlgorithmB.DoSomething;
Let's introduce the class of type:
type
TAlgorithmClass = class of TAlgorithm;
procedure Test;
var X:TAlgorithmClass; // This holds a reference to the CLASS, not a instance of the CLASS!
begin
X := TAlgorithm; // Valid because TAlgorithmClass is supposed to be a "class of TAlgorithm"
X := TAlgorithmA; // Also valid because TAlgorithmA is an TAlgorithm!
X := TAlgorithmB;
end;
TAlgorithmClass is a data type that can be used like any other data type, it can be stored in a variable, passed as a parameter to a function. In other words we can do this:
procedure CrunchSomeData(Algo:TAlgorithmClass);
begin
Algo.DoSomething;
end;
CrunchSomeData(TAlgorithmA);
In this example the procedure CrunchSomeData can use any variation of the algorithm as long as it's an descendant of TAlgorithm.
Here's an example of how this behavior may be used in a real-world application: Imagine a payroll-type application, where some numbers need to be calculated according to an algorithm that's defined by Law. It's conceivable this algorithm will change in time, because the Law is some times changed. Our application needs to calculate salaries for both the current year (using the up-to-date calculator) and for other years, using older versions of the algorithm. Here's how things might look like:
// Algorithm definition
TTaxDeductionCalculator = class
public
class function ComputeTaxDeduction(Something, SomeOtherThing, ThisOtherThing):Currency;virtual;
end;
// Algorithm "factory"
function GetTaxDeductionCalculator(Year:Integer):TTaxDeductionCalculator;
begin
case Year of
2001: Result := TTaxDeductionCalculator_2001;
2006: Result := TTaxDeductionCalculator_2006;
else Result := TTaxDeductionCalculator_2010;
end;
end;
// And we'd use it from some other complex algorithm
procedure Compute;
begin
Taxes := (NetSalary - GetTaxDeductionCalculator(Year).ComputeTaxDeduction(...)) * 0.16;
end;
Virtual Constructors
A Delphi Constructor works just like a "class function"; If we have a metaclass, and the metaclass knows about an virtual constructor, we're able to create instances of descendant types. This is used by TCollection's IDE Editor to create new items when you hit the "Add" button. All TCollection needs to get this working is a MetaClass for a TCollectionItem.
Yes a Collection would still be able to hold any descendant of TCollectionItem and to invoke methods on it. BUT, it wouldn't be able to instantiate a new instance of any descendant of a TCollectionItem. Calling TCollectionItem.Create constructs an instance of TCollectionItem, whereas
private
FItemClass: TCollectionItemClass;
...
function AddItem: TCollectionItem;
begin
Result := FItemClass.Create;
end;
would construct an instance of whatever class of TCollectionItem descendant is held in FItemClass.
I haven't done much with generic containers, but I think that given a choice, I would opt for the generic container. But in either case I'd still have to use a metaclass if I wanted to have the list instantiate and do whatever else needs to be done when an item is added in the container and I do not know the exact class beforehand.
For example an observable TObjectList descendant (or generic container) could have something like:
function AddItem(aClass: TItemClass): TItem;
begin
Result := Add(aClass.Create);
FObservers.Notify(Result, cnNew);
...
end;
I guess in short the advantage/benefit of metaclasses is any method/class having only knowledge of
type
TMyThing = class(TObject)
end;
TMyThingClass = class of TMyThing;
is able to construct instances of any descendant of TMyThing whereever they may have been declared.
Generics are very useful, and I agree that TObjectList<T> is (usually) more useful than TCollection. But class references are more useful for different scenarios. They're really part of a different paradigm. For example, class references can be useful when you have a virtual method that needs to be overridden. Virtual method overrides have to have the same signature as the original, so the Generics paradigm doesn't apply here.
One place where class references are used heavily is in form streaming. View a DFM as text sometime, and you'll see that every object is referred to by name and class. (And the name is optional, actually.) When the form reader reads the first line of an object definition, it gets the name of the class. It looks it up in a lookup table and retrieves a class reference, and uses that class reference to call that class's override of TComponent.Create(AOwner: TComponent) so it can instantiate the right kind of object, and then it starts applying the properties described in the DFM. This is the sort of thing that class references buy you, and it can't be done with generics.
I also would use a metaclass whenever I need to be able to make a factory that can construct not only one hard-coded class, but any class that inherits from my base class.
Metaclasses are not the term I am familiar with in Delphi circles however. I believe we call them class references, which has a less "magic" sounding name, so it's great that you put both common monikers in your question.
A concrete example of a place I have seen this used well is in the JVCL JvDocking components where a "docking style" component provides metaclass information to the base docking component set, so that when a user drags their mouse and docks a client form to the docking host form, the "tab host" and "conjoin host" forms that show grabber bars (similar in appearance to the title bar of a regular undocked window) can be of a user-defined plug-in class, that provides a customized appearance and customized runtime functionality, on a plug-in basis.
In some of my applications I have a mechanism that connects classes to forms capable of editing instances of one or more of that classes. I have a central list where those pairs are stored: a class refernce and a form class reference. Thus when I have an instance of a class I can lookup the corresponding form class, create a form from it and let it edit the instance.
Of course this could also be implemented by having a class method returning the appropriate form class, but that would require the form class to be known by the class. My approach makes a more modular system. The form must be aware of the class, but not the other way round. This can be a key point when you cannot change the classes.

Object crashing when in main program, but not when moved to unit

I've written a custom SDL GUI toolkit (source is on http://sourceforge.net/projects/lkgui/files/) and I'm having an issue with an inherited object.
When the object is within the main program, the constructor isn't called hence the program doesn't properly initialise the object and it crashes after some commands (Specifically, TStartGameButton inherits from GUI_Canvas inherits from GUI_Element and anything that is not defined in GUI_Element crashes the program with an EAccessViolation). When the object is placed within a unit, this problem goes away.
I understand that I could just leave it in the unit, but it will lead to some ugly code that could hopefully be avoided.
Has anyone any idea why this might be happening and how I may avoid it?
Old-style Delphi objects have been broken since the release of Delphi 2, perhaps earlier. They do not do inheritance well when they have fields of compiler-managed types, such as string or dynamic arrays. There was a discussion about it in 2004 on comp.lang.pascal.delphi.misc. Here was the code to reproduce it:
type
TBase = object
public
s: string;
end;
TDerived = object(TBase)
end;
procedure test;
var
obj: TDerived; //okay for TBase!
begin
assert(obj.s = '', 'uninitialized dynamic variable');
end;
And in fact it's only OK for TBase by accident because of how the function's prologue code happens to be generated. Putting additional code in that function can make it crash anyway.
Indeed, it's exactly as you've observed — old-style objects don't get initialized properly. Their string fields don't start out holding an empty string; instead, they hold garbage, and so it's not even possible to initialize them yourself without using something like FillChar.
This appears to be due to the variables being local variables. Unit-scope ("global") variables seem to work OK. Variables that are declared at unit scope but only used by the unit's initialization section, or at program scope and used only in the DPR file's main begin-end block, are treated by the compiler as local variables, so they're not set to all-bits-zero like their global counterparts. When you move your variable declaration to a unit but continue to use it in your DPR file, it's elevated to "global" status.
Your TGUI_Element type has a string member called DbgName, and it looks like that's the only string field you have in the type hierarchy. Take that out, or change it to ShortString, and I'll bet your crashes go away, at least temporarily.
Why are you giving all objects individual named constructors instead of making them virtual?
type tx = object
constructor init; virtual;
end;
txx = object(tx)
constructor init; virtual; // like override in Delphi classes.
end;
If you need a visual hierarchy to look at, have a look at Free Vision, it demonstrates nearly every facet of the TP object model
Oops apparantly virtual constructors are not possible in the TP model

Are Delphi interfaces inherited in subclasses

If I implement an interface on a base class will it be inherited by its sub classes, I know the functions/procedures will be, but I am more interested in whether I will be able to cast the subclass to the interface and then back to its original class.
What I am hoping I can do is pass objects of different base classes to a function, and then in the function determin there type and use them as appropriate.
Is this possible and is it the correct approach?
Update
to help clear up any confusion (or to create some more) here is what I would like to do (striped down to its core).
Interface
IMyInterFace = interface
['{B7203E50-F5CB-4755-9DB1-FB41B7B192C5}']
function MyFunction: Boolean;
end;
Base Class
type TMyObject = class(TInterfacedObject,IMyInterFace)
Sub Class
type TSubMyObject = class(TMyObject)
Another Class
type TMyOtherObject = class(TInterfacedObject,IMyInterFace)
Then the usage
procedure foo();
var obj:TSubMyObject;
begin
obj := TSubMyObject.Create();
SendInterfaceObject(obj);
end;
procedure bar();
var obj:TMyOtherObject;
begin
obj := TMyOtherObject.Create();
SendInterfaceObject(obj);
end;
procedure SendInterfaceObject(iobj:IMyInterFace);
begin
if (iobj is TSubMyObject) then
begin
//code here
end
else if (iobj is TMyOtherObject) then
begin
//code here
end;
end;
Update 2
I have updated the code abit so show what I am after better.
the //code here sections have little to do with the object that are passed to it, for example if this class is TAccounts and it was passed a TEmployee object it may pay there weekly pay but if it was a TInvoice then it would check to see if it needed paying and only pay it when the date was 2 days before the dead line.
the TEmployee/TInvoice may even come from out side classes asking for payments to be made.
this is just an example.
Yes, the interface is inherited by the subclass.
It's perfectly acceptable to cast from subclass to the interface.
However, and apologies if I'm reading your question wrong, but if "and then back to its original class" means . . .
You have Interface I, class A and class B.
A implements I, and B inherits A, you possibly can, but REALLY SHOULD NOT cast from A to B.
EDIT:
You want to go from B to I and back to B . . . but you already have a reference to B, if B is what you pass to your function, so you don't need to cast from I to B (unless were talking about a different object, then No, don't do it)
Going from I to B is the same as going from A to B, you're trying to cast up the inheritance chain, which really is something you shouldn't do. Needing to do this is a code smell, it tells you that you should try and solve this problem in a different way (possibly by redesigning you classes (e.g. adding more properties / methods to I), or just deciding that the function will only work with the sub class - working with the subclass 'B' will give you access to all the methods of A & I).
Can you edit your question and add some sample code of what you're trying to do?
EDIT 2
procedure SendInterfaceObject(iobj:IMyInterFace);
begin
if (iobj is TSubMyObject) then
begin
//code here
end;
end;
The 'If' statement in there is a bad idea, and breaks OO principals. If you need to do this then either
The interface definition is
insufficient, you might want to add a
Type property to the interface
allowing you to (if iObj.SomeProperty
= 1) then . . .)
The interface is simply not the
correct soluton to this problem, and
you should pass the reference as
TSubMyObject.
EDIT 3:
#mghie: I agree with you, what I didn't explain very well was that SomeProperty has some data that allows the function to branch there, removing the dependancy of type checking. SomeProperty shouldn't 'simply' replace the type check (e.g. by putting the class name in a property, then checking the class name) That is indeed exactly the same problem.
There is some essential difference between Subclasses that inherit the interface. This difference should be expressed by either
Exposing some item of data that can
then be used in the brach
e.g.
if(item.Color = Red) then
item.ContrastColor := Blue;
else
item.ContrastColor := Red;
Or through polymorphism e.g.
IEmployee defines a CalculatePay method, TManager and TWorker implement IEmployee, each with different logic in the CalculatePay methods.
If the intent was to do something like the first case, polymorphism could be overkill (polymorphism doesn't fix every problem).
EDIT 4
You say "the //code here sections have little to do with the object that are passed to it . . ." I'm sorry but that statement is incorrect, if you need to Pay an Employee, you need to know their 1) EmployeeCode 2) Their Salary Details 3) Their bank details etc, if you're charging an invoice you need 1) InvoiceNumber 2) Invoice Amount 3) CustomerCode to charge to etc . . . this is an ideal place for Polymorphism.
Lets say the function taking the interface checks to see if "Accounts" needs to do something with the object (e.g. Pay the employee, charge an Invoice etc). So we might call the function AccountsCheck. Inside Accounts check you will have a peice of logic specific to each sub class (to pay an employee, to charge the invoice . . .) This is an ideal candidate for Polymorphism.
On you interface (or on another interface, or as a virtual method on the sub class) Define an "AccountsCheck" method. Then each derived class gets its own implementation of Accounts check.
The code moves out of your humungous single AccountsCheck function, and into smaller functions on each sub class. This makes the code
More obvious in intent (each class
contains some logic for
AccountsCheck)
You're less likely to break SubClass
B's logic when fixing something in
AccountsCheck for C
It's easier to figure out exactly
what SubClass B's AccountsCheck logic
is, you've only to check 20 lines of
code in small AccountsCheck, not 200
in the General AccountsCheck)
There are more, "good reasons" for this, aif nyone wants to edit/post comments please do so.
If you find you need to share some logic between implementations of AccountsCheck, create some utility functions, don't reimplement the same wheel in each one.
Polymorphism is the solution to your problem.
My suggestion here would be to not cast against the class but instead cast against another interface. Change your TMyOtherObject to:
type
IOtherObjectIntf = interface
['{FD86EE29-ABCA-4D50-B32A-24A7E71486A7}']
end;
type
TMyOtherObject = class(TInterfacedObject,IMyInterFace,IOtherObjectIntf)
and then change your other routine to read:
procedure SendInterfaceObject(iobj:IMyInterFace);
begin
if Supports(iObj,IOtherObjectIntf) then
begin
//code here for TMyOtherObject
end
else
begin
//code here for other standard implementations
end;
end;
This way your "custom" code for the TMyOtherObject would also be applied to any of ITS descendants without any further custom code. The IOtherObjectIntf interface is used as nothing other than a "yep, I'm one of those" indicators which allows your code to branch properly. Sure, its laying waste to another Guid...but there are so many of them, who would notice? :)
The interface is inherited by the subclasses and you can cast the objects to the interface, but it is not safe(or recommended) to cast the interface to class. If you need to do this you are probably using interfaces the wrong way.
There seems to be some doubt on how your question is to be understood, and indeed in your comment to this answer you say that you want to "go from B to I to B".
This is indeed not recommended and only supported by using information about how interfaces are implemented on a class.
If I understand you correctly then what you want to do is to pass an interface to some method, and in that method do different things depending on what concrete class the interface was implemented by. It is however best to continue using interfaces once you start with them. You could let the interface have a method to return the implementing class, but you should not make any assumptions about what class the interface is implemented in - it costs you some of the benefits of programming against interfaces.
What you can do instead is create different interfaces, and implement some of them only in (some of) your descendant classes. Then you can use QueryInterface() or Supports() on the passed interface pointer. For your base class this will return nil, but for all descendant classes that implement the interface it will return a pointer that lets you call the methods only they have.
Edit: For example in the OmniThreadLibrary you will find:
IOmniWorker = interface
['{CA63E8C2-9B0E-4BFA-A527-31B2FCD8F413}']
function GetImplementor: TObject;
...
end;
which you could add to your interface. But again, IMHO the use of distinct interfaces is much better.
You can't cast an interface to an object directly (it is not what interfaces are intended for) but sometimes it so practical to be able to do it, that you can't resist...
If you really want to do like that, you can use the example "IOmniWorker" given by mghie directly in IMyInterFace:
IMyInterFace = interface
['{B7203E50-F5CB-4755-9DB1-FB41B7B192C5}']
function MyFunction: Boolean;
function GetImplementor: TObject;
end;
The function implementations look like that:
function TMyObject.GetImplementor: TObject;
begin
Result := Self;
end;
function TMyOtherObject.GetImplementor: TObject;
begin
Result := Self;
end;
SendInterfaceObject looks then like that:
procedure SendInterfaceObject(const iobj:IMyInterFace);
begin
if (iobj.GetImplementor is TSubMyObject) then
begin
//code here
end
else if (iobj.GetImplementor is TMyOtherObject) then
begin
//code here
end;
end;
By the way I have added a (very) small optimization: by passing iobj as "const" to the function you can avoid unnecessary reference counting.

Resources