views:

92

answers:

3

Are there any side effects to changing a class hierarchy's ancestor from TObject to TInterfacedObject so that I can implement interfaces further down the inheritance chain?

I've programmed in Delphi for several years but never encountered interfaces. I became accustomed to using them in other languages. Now that I'm involved in a Delphi project again I'd like to start taking advantage of them but I know they work a bit differently than in Java or C#.

+1  A: 

Aside from a few extra bytes in your instance size, no. That's probably the best way to do it.

Mason Wheeler
+4  A: 

If you already have existing code using the class you will probably have to modify a lot of it to keep references to interfaces instead of object instances. Interfaces are reference counted and released automatically, as a result, any reference to the implementor instance will become an invalid pointer.

TOndrej
In most cases the objects are created and destroyed in a single function. My main concern was whether reference counting interfered with manual memory management. Its a huge code base with very few unit tests so I planned to replace the references incrementally.
codeelegance
@codeelegance: Yes, interface counting replaces manual memory management. You can use one or the other, but not both, on any given object.
Mason Wheeler
@Mason So as long as I don't have an object reference and an interface reference pointing to the same object I should be alright?
codeelegance
@codeelegance: Exactly.
Mason Wheeler
+2  A: 

This will work fine as long as you inherit from the class below at the top (bottom?) of your hierarchy. This code ensures that your new classes dont free themselves - as is the default behaviour of TInterfaceObject - you are presumably already freeing them yourself and want to preserve this. This activity is actually exactly what TComponent in the VCL does - it supports interfaces but is not reference counted.

type


  TYourAncestor = class( TInterfacedObject )
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

  end;



implementation



function TYourAncestor.QueryInterface(const IID: TGUID; out Obj): HResult;
const
  E_NOINTERFACE = HResult($80004002);
begin
  if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
end;


function TYourAncestor._AddRef: Integer;
begin
  Result := -1   // -1 indicates no reference counting is taking place
end;

function TYourAncestor._Release: Integer;
begin
  Result := -1   // -1 indicates no reference counting is taking place
end;
Brian Frost
Let's say I didn't reimplement these three functions and attempted to manually free an object from an interface reference. What would be the result?
codeelegance
@codeelegance: the result would be a compiler error, it is not possible to free an object from an interface reference.
mjustin
You don't need to inherit from TInterfacedObject here, TObject implementing IUnknown would be fine.
tomazy