Behandlung der anonymen Methoden von Delphi in C++
Nach oben zu Behandlung von Delphi-Features in C++Builder - Index
Dieses Thema beschreibt einige Programmierfragen, die bei der Arbeit mit anonymen Methoden - eines der neuesten Delphi-Features - auftreten können.
Delphi implementiert anonyme Methodentypen (auch Methodenreferenzen genannt) über ein Interface, das eine Invoke(...)-Methode implementiert. Daher wird eine Methode, die einen Methodenreferenzparameter in Delphi ü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 Delphi ü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); }