RAD Studio
ContentsIndex
PreviousUpNext
How to Handle Delphi Anonymous Methods in C++

This topic describes some programming issues that you might encounter when dealing with anonymous methods, one of Delphi's newest features.  

Under the cover, Delphi implements anonymous methods types (also known as method references) via an interface that implements an Invoke(...) method. So a method that takes a method reference parameter in Delphi is exposed to C++ as a method that takes an interface. Here's an example:

interface

type

  TRefProc = reference to function (I, J: Integer): Integer;

  TTestClass = class
    public
      function TakeRefProc(RefProc: TRefProc; I, J: Integer): Integer;
  end;

The following is the .hpp file generated for the above:

__interface TRefProc;
typedef System::DelphiInterface <TRefProc> _di_TrefProc;

__interface TRefProc  : public System::IInterface 
{
public:
 virtual int __fastcall Invoke(int I, int J) = 0 ;
};

class PASCALIMPLEMENTATION TTestClass : public System::TObject
{
public:
 int __fastcall TakeRefProc(_di_TRefProc RefProc, int I, int J);
};

C++ code that seeks to specify a function or member function as a method reference parameter has to wrap the latter behind an interface that exposes an Invoke() method. A C++ template can be used to encapsulated such an interface. The following C++ code shows an example of a template that can be used to pass C++ methods or member functions as method references to Delphi.

enum _DummyType{};      // Parameter used as default

template <typename INTF,                       // Interface with Invoke
                typename F,                            // Function type
                typename R,                           // Return type
                typename P1 = _DummyType,  // Param #1
                typename P2 = _DummyType,  // Param #2
                typename P3 = _DummyType,  // Param #3
                typename P4 = _DummyType,  // Param #4
                typename P5 = _DummyType> // Param #5
class TMethodRef : public TInterfacedObject, public INTF

{
private:
  F callback;
public:
  TMethodRef(F _callback) : callback(_callback) {}

  HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject)
  { return TInterfacedObject::QueryInterface (riid, ppvObject); }
  ULONG STDMETHODCALLTYPE AddRef()
  { return TInterfacedObject::_AddRef(); }
  ULONG STDMETHODCALLTYPE Release()
  { return TInterfacedObject::_Release(); }

R __fastcall Invoke(P1 p1)
  {
    return callback(p1);
  }
  R __fastcall Invoke(P1 p1, P2 p2)
  {
    return callback(p1, p2);
  }
  R __fastcall Invoke(P1 p1, P2 p2, P3 p3)
  {
    return callback(p1, p2, p3);
  }
  R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4)
  {
    return callback(p1, p2, p3, p4);
  }
  R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
  {
    return callback(p1, p2, p3, p4, p5);
  }
};

The following code shows how to use the template shown above to pass a C++ routine as a method reference.

// C++ function we want to pass as a method reference.
int multiplyCallback(int i, int j)
{
  return i*j;
}


void UseRefProcFlat()
{
  std::auto_ptr<TTestClass> cls(new TTestClass());
  _di_TRefProc proc = new TMethodRef<TRefProc, int (*)(int, int), int, int, int>(multiplyCallback);
  int i = cls->TakeRefProc(proc, 10, 20);
  assert(i == 200);
}

You can also use the template to pass a member function as a method reference. The following code illustrates this:

class TMyClass {
public:
  int add(int i, int j) {
    return i+j;
  }
};
typedef int (__closure *TClosure)(int, int);

void UseRefProcMember()
{
  TMyClass myClass;

  std::auto_ptr<TTestClass> cls(new TTestClass());
  _di_TRefProc proc = new TMethodRef<TRefProc, TClosure, int, int, int>(&myClass.add);

  int i = cls->TakeRefProc(proc, 10, 20);
  assert(i == 30);
}
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!