__closure

From RAD Studio
Jump to: navigation, search

Go Up to C++ Keyword Extensions


Category

Keyword Extensions

Syntax

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

Description

There are two kinds of function pointers that can be used in C++. The first is a simple pointer to a global function (not a member of a class). When dealing with class member functions, a simple pointer to a method is not sufficient to make a call. Instead, two pointers are required: one for the originating object and the second for the method address.

All VCL component events are declared as closures, in order to allow methods of a class to be called when the event is fired. The following code is an excerpt from the Classes.hpp header, showing the declaration of the TNotifyEvent, used in many events in the VCL (e.g. OnClick).

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

The following example shows how a normal, global function pointer type is declared:

typedef void (*PointerToAFunction)();

It is used as follows:

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

To make this function pointer type into a method pointer, simply add __closure as follows:

typedef void (__closure *PointerToAFunction)();

The method pointer is used as follows:

/* Assigning a method to the method pointer */
PointerToAFunction a = &(someObject.SomeMemberFunc);
Attention: When declaring closures with constants and pointers in the published section of a class, use a typedef for the pointer as follows:
 typedef int*
 typedef void _fastcall (_closure MyClosure)(const IntPtr piVal);

Examples

The __closure keyword is used to declare a special type of pointer to a member function. In standard C++, the only way to get a pointer to a member function is to use the fully qualified member name, as shown in the following example:

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

However, you cannot assign a pointer to a member of a derived class to a pointer to a member of a base class. This rule (called contravariance) is illustrated in the following example:

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

The __closure keyword extension allows you to skirt this limitation, and more. Using a closure, you can get a pointer to member function for an object (for example, a particular instance of a class). The object can be any object, regardless of its inheritance hierarchy. The pointer of the object is automatically used when calling the member function through the closure. The following example shows how to declare and use a closure. The base and derived classes provided earlier are assumed to be defined.

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

For a code example, see TRegExReplace (C++).

Closures also work with pointers to objects, as illustrated in this example:

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

Notice that we are passing a pointer to an instance of the derived class, and we are using it to get a pointer to a member function in the base class--something standard C++ does not allow us to do.

Closures are a key part of the C++Builder RAD Studio environment. They give us the ability to assign an event handler in the Object Inspector. For example, a TButton object has an event called OnClick. In the TButton class, the OnClick event is a property that uses the __closure keyword extension in its declaration. The __closure keyword allows us to assign a member function of another class (typically a member function in a TForm object) to the property. When you place a TButton object on a form, and then create a handler for the OnClick event of the button, C++Builder creates a member function in the button’s TForm parent, and assigns that member function to the OnClick event of TButton. This way, the event handler is associated with that particular instance of TButton, and no other.

See Also

Code Examples