Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

C++ Delegates and Borland's C++ Builder Event Handling - Part I

4.60/5 (6 votes)
26 Nov 2009CPOL3 min read 25.6K   244  
Describes how Borland could bybass standard C++ restrictions via __closure keyword

Introduction

This article is partitioned into two main parts.

Part I discusses standard C++ member-function-pointers (MFP), which is different from normal function-pointers. It also illustrates the restrictions on these type of pointers and how Borland's C++ Builder bypasses them via its special type of MFP __closure.

Part II shows an application of using this type of MFP. It explains in detail how Borland uses their own type of MFP to handle Windows Events and how it is fascinating rather MFC style or Win32 API style.

Backgrounds

I assume that the reader has enough background in order to use MFP. I know its syntax is a little stupid, but I didn't explain it in details. Instead I used comments to explain what lines of code do.
Also, I assume that the reader is aware of Inheritance and polymorphism.

Part I - Closures: An introduction

Closures are a very useful feature in C++ builder. To illustrate this, let's talk first about normal member-function-pointers in C++.
Try the following code:

C++
#include <stdlib.h>
class Base{public:int baseFunc(int){}};
class Drvd:public Base{public:int drvdFunc(int){}};
class Alone{public:int aloneFunc(int){}};
//----------------------- Normal member-function-pointers ---------------
int main() {
    int (Base::*funcPtr)(int); 	// MFP of type Base::*
    funcPtr = &Drvd::baseFunc; 	// member-function pointed to
    Drvd ob; 			// type of calling object
    (ob.*funcPtr)(2); 		// calling of MFP is from here
    system("pause");
    return 0;
}

This code shows the behavior of normal C++ member-function-pointers (MFP).
As we see, MFP of type Base::* can point to the following:

  • Base::baseFunc - and can be called from object of type Base/Drvd.
  • Drvd::baseFunc - and can be called from object of type Base/Drvd.
But cannot point to the following:
  • Drvd::drvdFunc
  • Alone::aloneFunc

If we changed MFP’s type to be Drvd::*, the situation is going to be changed slightly to point to:

  • Base::baseFunc - and can be called form object of type Drvd
  • Drvd::baseFunc - and can be called from object of type Drvd
  • Drvd::drvdFunc - and can be called from object of type Drvd

But, it cannot point to:

  • Alone::aloneFunc

Finally if our MFP be of type Alone::*, it can only point to:

  • Alone::aloneFunc - and can be called from object of type Alone

And it cannot point to:

  • Base::baseFunc
  • Drvd::baseFunc
  • Drvd::drvdFunc

Borland’s "__closure" Keyword

Borland has added a new keyword to language to bypass restrictions set by the standard C++.
This keyword is __closure.

So far we have three restrictions that are:

  • MFP of type Base cannot point to Drvd member-functions that are new (not inherited).
  • MFP cannot point to any member-function that is in a class out of inheritance hierarchy Base/Drvd and Alone for example.
  • We cannot assign a pointer to member-function to our MFP using object name, instead we have to use the fully qualified name Class::member-function. This would be very useful if solved, since objects may change polymorphically at run-time.

Actually the first and the second restrictions are very similar. In other words our goal is to make any MFP point to any member-function in any class that is either in the inheritance hierarchy or not.

Let’s see how Borland solved this problem using the __closure keyword.

C++
#include <stdlib.h>
class Base{public:int baseFunc(int){}};
class Drvd:public Base{public:int drvdFunc(int){}};
class Alone{public:int aloneFunc(int){}};
//---------------------- Borland's C++ Buildre's Closures ---------------
int main() {
    int ( __closure *funcPtr)(int); 	// special MFP of type __closure
    Drvd ob;
    funcPtr = ob.drvdFunc; 		// member-function pointed to
    funcPtr(2); 			// calling of closure is from here
    system("pause");
    return 0;
}

Try to point funcPtr to any member function and see the result. Just make sure that it has the same parameters list and and the same return type.

Now let’s see how solving the third problem would be very useful. Check out this code:

C++
#include <iostream.h>
class Base{public:virtual int baseFunc(int){cout << "i am baseFunc in Base class\n" ; }};
class Drvd:public Base{public:int baseFunc(int)
	{cout << "i am baseFunc in Drvd class\n" ; }};
//---------------------- Borland's C++ Buildre's Closures ---------------
int main() {
    int ( __closure *funcPtr)(int); 	// special MFP of type __closure
    Base *ob = new Base();
    funcPtr = ob->baseFunc; 	// member-function pointed to
    funcPtr(2); 			// calling of MFP is from here
    delete ob;
    ob = new Drvd(); 		// polymorphic behaviour
    funcPtr = ob->baseFunc;
    funcPtr(2);
    delete ob; ob=NULL;
    system("pause");
    return 0;
}

Isn’t this great? Thank you Borland.

See you in Part II.

History

  • 26th November, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)