Behandlung der anonymen Methoden von Object Pascal in C++
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);
}