Free Educational Resource Center for teachers and students. Includes Interviews,
Sourcecode, Free Software, Research Papers, Articles, Tutorials and much more..
     R E S E A R C H A C T I V I T Y . C O M
Our Fellow Research Center for Ph.D Schollars
Home About Submit & Earn Archives: C And C + + Programming » Dev Packages » Interviews » Php Mysql Programming » Windows Programming
search
C And C Plus Plus Programming > easy cplusplus delegates generic properties closures thunks

Easy C++ - Delegates / Generic Properties / Closures / Thunks

Purpose of this document is not to start yet another discussion, but taking implementation of delegates in C++ (which nomrally most of C++ compilers don't support) to one more step ahead. And make it REAL EASY for developers to add such feature to their existing C++ program to compile on any C++ compiler.

What are we talking about?

We are talking about a member (treated as variable) of certain class that has 2 type of functions associated with, one function that returns the value of certain type when said data member is asked to return a value, and other function to set the value when said data member is assigned a value.

Understanding using simple example:
Take example of a Button on a dialog, Button is basically a class and has a member called "width". When width is assigned a value the button's width is physically changed on the idalog surface and when we assign this member to an "int" type variable, said "width" property returns the width of the button.


Button b;

b.width = 100; //setting / assigning the value, change button width to 100 pixels
int bw = b.width; //getting the value, get button's current width in pixels


Now, if the data member "width" was a normal integer "int" it wont affect the width of the button physically, so basically we have to create "width" in a way that it should affect button width when assigned a value, and must retun button's physical width when required. For this we need to attach two functions to this member, one function for changing button's width, and other for getting button's width.

How to accomplish this?

To accomplish this, we will not define data member 'width' as int but define member 'width' someway as property (in other words) a class that has "operator =" , and has 2 functions that we bind to this tiny Button class for getting and setting data value, and performing extra functionality (e.g. affecting button's width). So we need something like:



class Button {
public:
<SOMETHING ELSE BUT NOT int> width;

void set_value(int newValue)
{
//change button width
}

int get_value()
{
return ??; //button's width;
}
};


Question is how to attach the two little member functions 'set_value' and 'get_value' to data member 'width', so that they get called automatically when 'width' is used in either way.


Little into depth. This is what keywords, property in Microsoft Visual C++, delegates in C#, and closure in Borland C++ Builder are used. But they are not cross platform and not supported by all C++ compilers.

For example (keyword):
property not supported by GCC
property not supported by Borland C++
closure not supported by GCC
closure not supported by Microsoft VC++
property and closure both not supported by Watcom C++
property and closure both not supported by LCC
property and closure both not supported by Intel C++ (am not sure about this)

To overcome this problem, we have many implementations for generic properties
* some use tempaltes
* some use hardcoded class name to use with scope resolution operator
* some utilize #define keyword, etc etc.


SO WHY YET ANOTHER IMPLEMENTATION?

keyword "property" is available in MSVC++ only.
keyword "closure" is available in Borland C++ only.

What about GCC, and compilers on other platforms like Linux and Mac OSX?

Using other than (builtin implementations) "property" and "closure", mostly a new class is created for each data member, which becomes bulky. In result it may not affect program speed (depends), but definitely increases final executable size very much. And after all, it is not a good idea to have new class for thousands of data members.

In all implementations we have two member functions bound to such properties. But we know that ISO forbids assigning address of member function in a class, in result we have to point to a member function including class scope, such as &Button::*get_value or &Button::*set_value. But, wait, this is specific to class Button, and ofcourse we will end up with templates to resolve this problem.


Now question arrives?
WHY DO WE BIND MEMBER FUNCTIONS?

Because we like our member functions to access all elements of the class (they are in), either public, private, and/or protected.

I had an idea last night, WHY NOT USE "friend" FUNCTIONS? (if it has already been implemented, forgive me I neve saw it)

A "friend" function has access to all of private, protected, as well as public data. Which will result in more generic class for properties imnplementation. Create a type once and use it multiple times. So, I wrote 2 macros bacially, one that creates the abstract class (not "abstract of c++" I would say a new type), and the other resolves the class pointer from long, using casting "reinterpret_cast".

Usage:


#include "delegate.h"

CREATE_PROPERTY_TYPE(int, intProp);

class Button {
public:
intProp width; //generic property of type "int"
};


Now it is time to bind some "friend" functions


class Button {
public:
intProp width;

Button() {
// bind property to 2 new friend functions rather than member functions

width.bind( get_width , set_width , (long)this );

}

// bound "friend" functions

friend int get_width(long);
friend int set_width(long, int);
};



What is this?

width.bind( get_width , set_width , (long)this );


We called the function "bind" that is memhber of new property class we created,
and then we passed it arguments:

1. getter - get_width
2. setter - set_width
3. pointer to current class to reuse in friend functions


COMPULTIONS:

1. First argument of each get and set functions must be "long" which will be used as class pointer.
2. In the set function 2nd argument will be the type of variable "new class type" was created for.
3. Set function must also have return type as property type, even if it is not returning any value.


Now implement the boud functions, they can be implemented outside but am implementing them
within class for clear idea.


class Button {
public:
intProp width;

HWND hwnd; //assumed handle to Button window


Button(HWND han=NULL) {
this->hwnd = han;
width.bind( get_width , set_width , (long)this );
}


friend int get_width(long __CP) {
Button *cls = reinterpret_cast<Button *> (__CP); //get access to class pointer

RECT r;
GetWindowRect(cls->hwnd,&r);
return r.right-r.left;
}

friend int set_width(long __CP, int v) {
Button *cls = reinterpret_cast<Button *> (__CP); //get access to class pointer

RECT r;
GetWindowRect(cls->hwnd,&r);
MoveWindow(cls->hwnd,r.left,r.top,value,r.bottom-r.top,true);
return value;
}
};


Further summarizing the interpretation portion of the code:

CREATE_CLASS_POINTER(Button, cls);

instead of using

//Button *cls = reinterpret_cast<Button *> (__CP);

Compultion:

1. First argument variable name of both get and set functions must be __CP, if you wish to use said "CREATE_CLASS_POINTER" macro, or create your own.




USING THIS "Button" CLASS:


Button b( GetDlgItem(myDlg, 101) );
btn.width = 100;
int bw = btn.width;



Summary of all talk:

1. Cross platform code
2. All C++ compilers supopport
3. Small foot-prints in final executable
4. Not bulky for execution
5. Can be used even if you have no idea what are function pointers and generic properties


IMPLEMENTATION OF "CREATE_PROPERTY_TYPE" in delegate.h

#define CREATE_PROPERTY_TYPE(__USERTYPE, __TYPENAME) \
class __TYPENAME {\
typedef __USERTYPE (*__TYPENAME##_GP)(long);\
typedef __USERTYPE (*__TYPENAME##_SP)(long, __USERTYPE);\
\
private:\
__TYPENAME##_GP gf;\
__TYPENAME##_SP sf;\
long cls;\
public:\
__TYPENAME() {\
gf = NULL;\
sf = NULL;\
}\
void bind(__TYPENAME##_GP vgf,__TYPENAME##_SP vsf, long vcls=0) {\
gf=vgf;\
sf=vsf;\
cls=vcls;\
}\
__TYPENAME(__TYPENAME##_GP vgf,__TYPENAME##_SP vsf, long vcls=0) {\
this->bind(vgf,vsf,vcls);\
}\
__USERTYPE operator = (__USERTYPE v) {\
(*sf)(cls, v);\
return (__USERTYPE)v;\
}\
__USERTYPE operator = (__TYPENAME & v) {\
(*sf)(cls, v);\
return (__USERTYPE)v;\
}\
operator __USERTYPE () const {\
return (__USERTYPE)(*gf)(cls);\
}\
bool operator == (__USERTYPE v) {\
return ( (__USERTYPE)(*gf)(cls) == v );\
}\
bool operator != (__USERTYPE v) {\
return ( (__USERTYPE)(*gf)(cls) != v );\
}\
};\



IMPLEMENTATION OF "CREATE_CLASS_POINTER" in delegate.h


#define CREATE_CLASS_POINTER(__CLASS, __VAR) __CLASS * __VAR = reinterpret_cast <__CLASS *> (__CP);


SAMPLE WINDOWS PROGRAM (changes and retrieves width of a window):


#include <windows.h>
#include "delegate.h"

/*
C++ generic properties demostration program
Scenario:

Create a class window, which has a generic property
"width". When property width is assigned a value,
it will resize the window to assigned value, and equally
returns the width of the window when property itself is
assign to some other variable of same type.

*/


CREATE_PROPERTY_TYPE(int, intProp); //Create new property type

class Window {
public:
intProp width;
HWND hwnd;

Window(HWND=NULL);

//friend bound functions
friend int get_width(long);
friend int set_width(long, int);
};

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
HWND dlg = CreateWindowEx(
0,
WC_DIALOG,
TEXT("My Window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100,100,200,200,NULL,NULL,NULL,NULL
);

Window w(dlg);

MessageBox(dlg, TEXT("Now we will assign property value which will affect the width of the window"),TEXT(""),0);

w.width = 500; //notice this

TCHAR temp[100];

int wid = w.width; // notice this

wsprintf(temp,TEXT("New width is %d"),wid);

MessageBox(dlg,temp,TEXT(""),0);

return 0;
}



//implementation of constructor and bound functions
Window::Window(HWND han) {
this->hwnd = han;
width.bind( get_width , set_width , (long)this );
}
int get_width(long __CP) {
CREATE_CLASS_POINTER(Window, cls);

RECT r;
GetWindowRect(cls->hwnd,&r);
return r.right-r.left;
}

int set_width(long __CP, int value) {
CREATE_CLASS_POINTER(Window, cls);

RECT r;
GetWindowRect(cls->hwnd,&r);
MoveWindow(cls->hwnd,r.left,r.top,value,r.bottom-r.top,true);
return value;
}