Behandlung der anonymen Methoden von Object Pascal in C++

Aus Appmethod Topics
Wechseln zu: Navigation, Suche

Nach oben zu Behandlung von Object Pascal-Features in Appmethod C++ - Index

Dieses Thema beschreibt einige Programmierfragen, die bei der Arbeit mit anonymen Methoden - eines der neuesten Object Pascal-Features - auftreten können.

Object Pascal implementiert anonyme Methodentypen (auch Methodenreferenzen genannt) über ein Interface, das eine Invoke(...)-Methode implementiert. Daher wird eine Methode, die einen Methodenreferenzparameter in Object Pascal übernimmt, für C++ als eine Methode bereitgestellt, die ein Interface übernimmt. Hierzu ein Beispiel:

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

Im Folgenden finden Sie die für den obigen Quelltext erzeugt .hpp-Datei:

 __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, der eine Funktion oder eine Member-Funktion als einen Methodenreferenzparameter festlegt, muss den Parameter hinter einem Interface angeben, das eine Invoke()-Methode bereitstellt. Mit einer C++-Template kann ein solches Interface gekapselt werden. Der folgende C++-Code zeigt ein Beispiel einer Template, mit der C++-Methoden oder Member-Funktionen als Methodenreferenzen an Object Pascal übergeben werden können.

 enum _DummyType{};      // Parameter, der als Vorgabe verwendet wird
 
 template <typename INTF,   // Interface mit Invoke
                 typename F,   // Funktionstyp
                 typename R,   // Rückgabetyp
                 typename P1 = _DummyType,  // Parameter #1
                 typename P2 = _DummyType,  // Parameter #2
                 typename P3 = _DummyType,  // Parameter #3
                 typename P4 = _DummyType,  // Parameter #4
                 typename P5 = _DummyType> // Parameter #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);
   }
 };

Der folgende Code zeigt, wie mit der obigen Template eine C++-Routine als Methodenreferenz übergeben wird.

 // C++-Funktion, die als Methodenreferenz übergeben werden soll.
 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);
 }

Mit dieser Template kann auch eine Member-Funktion als Methodenreferenz übergeben werden. Der folgende Code zeigt dies:

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

Siehe auch