__closure

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Schlüsselwort-Erweiterungen in C++


Kategorie

Schlüsselwort-Erweiterungen

Syntax

<type> ( __closure * <id> ) (<param list>);

Beschreibung

In C++ können zwei Arten von Funktionszeigern verwendet werden. Die erste ist ein einfacher Zeiger auf eine globale Funktion (nicht auf einen Member einer Klasse). Bei Klassen-Member-Funktionen ist ein einfacher Zeiger auf eine Methode für einen Aufruf nicht ausreichend, sondern es sind zwei Zeiger erforderlich: einer für das Objekt und der zweite für die Methodenadresse.

Alle VCL-Komponentenereignisse sind als Closures deklariert, damit Methoden einer Klasse aufgerufen werden können, wenn das Ereignis ausgelöst wird. Der folgende Quelltext ist ein Auszug aus dem Header Classes.hpp, der die Deklaration von TNotifyEvent zeigt, das in vielen Ereignissen in der VCL (z. B. in OnClick) verwendet wird.

typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);

Das folgende Beispiel zeigt, wie ein normaler, globaler Funktionszeigertyp deklariert wird:

typedef void (*PointerToAFunction)();

Er wird folgendermaßen verwendet:

/* Assigning a function to the function pointer */
PointerToAFunction a = SomeGlobalFunc;

Um den Funktionszeigertyp in einen Methodenzeiger umzuwandeln, müssen Sie nur __closure hinzufügen:

typedef void (__closure *PointerToAFunction)();

Der Methodenzeiger wird folgendermaßen verwendet:

/* Assigning a method to the method pointer */
PointerToAFunction a = &(someObject.SomeMemberFunc);

Beispiele

Mit dem Schlüsselwort __closure wird ein spezieller Typ eines Zeigers auf eine Member-Funktion deklariert. In Standard-C++ kann ein Zeiger auf eine Member-Funktion nur mit dem voll qualifizierten Member-Namen erstellt werden, wie im folgenden Beispiel gezeigt:

class base {
public:
    void func(int x) {
    };
};

typedef void(base::*pBaseMember)(int);

int main(int argc, char * argv[])
{
    base baseObject;
    pBaseMember m = &base::func; // Get pointer to member ‘func’.

    // Call ‘func’ through the pointer to member.
    (baseObject.*m)(17);
    return 0;
}

Sie können jedoch keinen Zeiger auf einen Member einer abgeleiteten Klasse einem Zeiger auf einen Member einer Basisklasse zuweisen. Diese Regel (als Kontravarianz bezeichnet) wird im folgenden Beispiel illustriert:

class base {
public:
	void func(int x) {
	};
};

typedef void(base::*pBaseMember)(int);

class derived : public base {
public:
	void new_func(int i) {
	};
};

int main(int argc, char * argv[]) {
	derived derivedObject;
	pBaseMember m = &derived::new_func; // ILLEGAL
	return 0;
}

Mit der Schlüsselwort-Erweiterung __closure können Sie diese Beschränkung umgehen. Mit einem Closure lässt sich ein Zeiger auf eine Member-Funktion für ein Objekt (d. h. eine bestimmte Instanz einer Klasse) erstellen. Das Objekt kann jedes beliebige Objekt – unabhängig von seiner Vererbungshierarchie – sein. Der Zeiger auf dieses Objekt wird automatisch beim Aufruf der Member-Funktion über das Closure verwendet. Das folgende Beispiel zeigt, wie ein Closure deklariert und eingesetzt wird. Dabei wird davon ausgegangen, dass die Basis- und abgeleiteten Klassen bereits definiert sind.

class base {
public:
	void func(int x) {
	};
};

typedef void(base::*pBaseMember)(int);

class derived : public base {
public:
	void new_func(int i) {
	};
};

int main(int argc, char * argv[]) {
	derived derivedObject;
	void(__closure * derivedClosure)(int);

	// Get a pointer to the ‘new_func’ member.
	// Note the closure is associated with the
	// particular object, ‘derivedObject’.
	derivedClosure = derivedObject.new_func;

	derivedClosure(3); // Call ‘new_func’ through the closure.
	return 0;
}

Ein Codebeispiel finden Sie unter TRegExReplace (C++).

Closures arbeiten auch mit Zeigern auf Objekte, wie im folgenden Beispiel:

class base {
public:
	void func(int x) {
	};
};

typedef void(base::*pBaseMember)(int);

class derived : public base {
public:
	void new_func(int i) {
	};
};

// Closure with pointer to object
void func1(base * pObj) {
	// A closure taking an int argument and returning void.
	void(__closure * myClosure)(int);

	// Initialize the closure .
	myClosure = pObj->func;

	// Use the closure to call the member function.
	myClosure(1);
	return;
}

int main(int argc, char * argv[]) {
	derived derivedObject;
	void(__closure * derivedClosure)(int);

	derivedClosure = derivedObject.new_func; // Same as before...
	derivedClosure(3);

	// We can use pointers to initialize a closure, too.
	// We can also get a pointer to the ‘func’ member function
	// in the base class.
	func1(&derivedObject);
	return 0;
}

Beachten Sie bitte, dass ein Zeiger an die Instanz der abgeleiteten Klasse übergeben wurde, und dass damit ein Zeiger auf die Member-Funktion in der Basisklasse erstellt wurde – das wäre in Standard-C++ nicht zulässig.

Closures sind ein Schlüsselkonzept in der RAD Studio-Umgebung für C++Builder. Sie ermöglichen das Zuweisen einer Ereignisbehandlungsroutine im Objektinspektor. Angenommen, ein TButton-Objekt hat das Ereignis OnClick. In der Klasse TButton ist das Ereignis OnClick eine Eigenschaft, die die Schlüsselwort-Erweiterung __closure in ihrer Deklaration verwendet. Das Schlüsselwort __closure ermöglicht das Zuweisen einer Member-Funktion einer anderen Klasse (normalerweise einer Member-Funktion in einem TForm-Objekt) zu der Eigenschaft. Wenn Sie ein TButton-Objekt auf einem Formular platzieren und dann eine Behandlungsroutine für das Ereignis OnClick für TButton erstellen, legt C++Builder eine Member-Funktion in dem TButton übergeordneten TForm an und weist diese Member-Funktion dem OnClick-Ereignis von TButton zu. Auf diese Weise wird die Ereignisbehandlungsroutine dieser Instanz von TButton und keiner anderen zugeordnet.

Siehe auch

Codebeispiele