Show: Delphi C++
Display Preferences

How to Handle Delphi Anonymous Methods in C++

From RAD Studio
Jump to: navigation, search

Go Up to Handling Delphi Features in C++Builder Index

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);
 }

See Also

Personal tools
In other languages