Dynamic function calling
Friday, December 25, 2009 10:51:24 AM
This post will talk about dynamic call a function or method with dynamic parameter.
i suppose that we have some electrical elements are attached to a electrical network. when the switch is turned on, it becomes a electrical circuit and all electrical elements are turned on.
if you program a program to demo that. may be it same as bellow:
class cElecCircuit
{
cElecElem* m_aElems[MAX_ELEM];
int m_iElemCount;
BOOL Add(cElecElem* pElem)
{
if (m_iElemCount < MAX_ELEM)
{
m_aElems[m_iElemCount++] = pElem;
return TRUE;
}
return FALSE;
}
void OnClosed()
{
for( int i = 0; i < m_iElemCount ; i++)
m_aElems[i]->TurnOn();
}
void OnOpened()
{
}
};
class cElecElem
{
cElecCircuit* m_pElecCirc;
virtual void TurnOn() = 0;
};
class cElecLight : public cElecElem
{
void TurnOn()
{
...
}
};
class cTV : public cElecElem
{
void TurnOn()
{
...
}
};
class cPowerSource
{
public:
cElecCircuit* m_pCircuit;
void SwitchOn()
{
m_pCircuit->OnClosed();
}
void SwitchOff()
{
m_pCircuit->OnOpened();
}
};
Now, Everything is ok . But when a rat is attached to The electrical network then what happen ???
There are many ways to resolve this problem, change design of your classes, change process of some method, use template...
But actually, cRat should not delivery class of cElecElm, class design and their processing need to changed if something new come from outside such as another module need to call a function when switch turn on event happens.
There is a way to resolve it and the solution is called: "Dynamic function calling".
Problem
In fact, we need register a callback function or method when some event happen that them will be caught by another module (is called server module). You can use function pointer in case function or template in case method.
// use function pointer in case function
RETTYPE (*FunctionType)(<Parameter List>)
RETTYPE Invoke(FunctionType pFunc)
{
return pFunc(<Parameters>);
}
// use method pointer in case method
template<typename RETTYPE, class T,...>
typedef RETTYPE (T::*MethodType) (<Parameter List>)
template<typename RETTYPE, class T,...>
RETTYPE Invoke(T *Object, MethodType pMethod)
{
return (T->*pMethod)(<Parameters>);
}
If you use this way, you must use many type of callback function or method and you must change design
and define new type of callback when you need to change <Parameter List> or RETTYPE...
So, this way is not good.
Solution
There is a way to invoke a function or method with dynamic parameter type, parameter count and return type.
Here it is, Caller class.
i will show you some its main method.
class CALLER_API cCaller
{
public:
/*************************************************************************/
/* Constructor */
/* Param: */
/* 1. [in] pMethod : Method pointer or function pointer */
/* 2. [in opt]pMethodOwner : Object pointer, if pMethodOwner is */
/* not null, the pMethod will be */
/* treated as method pointer and it will*/
/* be called with pMethodOwner context */
/* if pMethodOwner is null then pMethod */
/* will be treated function pointer */
/*************************************************************************/
cCaller(void* pMethod,void* pMethodOwner = NULL);
virtual ~cCaller();
/*************************************************************************/
/* Push a parameter into parameter array, they are parameter list of */
/* the callback */
/* Param: */
/* 1. [in]pParamValue: Pointer point to a parameter */
/* 2. [in]iSize : size of parameter */
/* Return: */
/* Index of the parameter in array. In case failed this function */
/* return -1 */
/*************************************************************************/
int PushParam(void* pParamValue,unsigned int iSize);
/*************************************************************************/
/* remove a parameter at the end of parameter array */
/*************************************************************************/
void PopParam();
/*************************************************************************/
/* remove all parameter */
/*************************************************************************/
void ClearParams();
/**************************************************************************/
/* invoke first callback in list */
/**************************************************************************/
void Invoke();
/**************************************************************************/
/* invoke first callback in list and receive a value that will return from*/
/* the callback */
/**************************************************************************/
void* Invoke(void* pReturnValue, int Size);
/**************************************************************************/
/* invoke first callback in list and return a float value that will */
/* return from the callback */
/* You should use this method if the callback return a float value */
/**************************************************************************/
float Invokef();
/**************************************************************************/
/* invoke first callback in list and return a double value that will */
/* return from the callback */
/* You should use this method if the callback return a double value */
/**************************************************************************/
double Invoked();
/**************************************************************************/
/* invoke all callback in list, from 2nd caller in list, each caller */
/* will be added all parameter of the first */
/* Ex: The first has 2 parameter */
/* The Second has 1 parameter */
/* At invoke time, the first will invoke with 2 parameter, */
/* and the second is 3 */
/**************************************************************************/
void Invokes();
/**************************************************************************/
/* push a parameter pointer */
/* at the time compile this library default parameter size is 32 bit */
/**************************************************************************/
int PushParamPointer(void* pParamPointer);
};
Usage
-----------------------------------------
if the callback function is
void CallMe( int iParam)
{
...
}
then the Caller will invoke it is.
cCaller c(CallMe);
int iParam = 0;
c.PushParam(&iParam,sizeof(int));
c.Invoke();
------------------------------------------
if the callback function is
void CallMe( int &iParam)
{
...
}
or
void CallMe( int *pParam)
{
...
}
then the Caller will invoke it is.
cCaller c(CallMe);
int iParam = 0;
int* pParam = &iParam;
c.PushParam(&pParam,sizeof(void*));
c.Invoke();
or
cCaller c(CallMe);
int iParam = 0;
c.PushParamPointer(&iParam);
c.Invoke();
Library
class : cCaller
Header : Caller.h
Library: Caller.lib (for compiling)
Dll : Caller.dll (for runtime)
Caller API
Demo
Solution Demo & Usage Demo
Note
This library was compiled in 32 bit compiler, so it may be not work correctly in 64 bit application.







