這個(gè)方法可以實(shí)現(xiàn)按照統(tǒng)一的接口來(lái)調(diào)用類成員函數(shù),或者靜態(tài)函數(shù)和非類成員函數(shù). 主要原理很簡(jiǎn)單, 就是保存類對(duì)象指針和函數(shù)指針, 需要調(diào)用的時(shí)候就根據(jù)類對(duì)象指針是否為空來(lái)使用不同的方式調(diào)用函數(shù).
首先, 我們需要一個(gè)把成員函數(shù)指針轉(zhuǎn)化成void *的東西..(強(qiáng)制轉(zhuǎn)換似乎是不行的), 因?yàn)槲覀冃枰殉蓡T函數(shù)指針保存起來(lái), 又不想讓用戶寫函數(shù)指針類型描述, 那只能轉(zhuǎn)換成void*比較方便.
這里我們使用 聯(lián)合地址轉(zhuǎn)換 的方法.
template <typename T1, typename T2>
struct _T2T{
union {
T1 _tv1;
T2 _tv2;
};
};
template <typename T1, typename T2>
inline T1 t2t( T2 tv2 )
{
typedef struct _T2T<T1, T2> * PT2T;
PT2T pt = (PT2T)&tv2;
return pt->_tv1;
}
轉(zhuǎn)換方法就是 t2t<void*>( &ClassName::FuncName );
然后, 我們來(lái)構(gòu)造一個(gè)可以用 this 指針和 函數(shù)指針來(lái)進(jìn)行函數(shù)調(diào)用的東西.....這里使用了我之前隨筆里介紹的多參數(shù)定義宏, 用來(lái)生成多參數(shù)的函數(shù)調(diào)用.
struct callfunction
{
class nullclass{};
template <typename TRet>
static inline TRet callauto( void * pThis, void * pFunc ){
if( pThis == NULL )
return callnothis<TRet>( pFunc );
return callwiththis<TRet>( pThis, pFunc );
}
#define DEFINE_CALLFUNC_AUTO_WITH_PARAM( paramcount ) template <typename TRet, DP_STMP_##paramcount(typename, Tp)>\
static inline TRet callauto( void * pThis, void * pFunc, DP_MTMP_##paramcount(Tp, p ) ){\
if( pThis == NULL )\
return callnothis<TRet>( pFunc, LP_SNMP_##paramcount( p ) );\
else\
return callwiththis<TRet>( pThis, pFunc, LP_SNMP_##paramcount( p ) );\
}
DEFINE_CALLFUNC_AUTO_WITH_PARAM(1);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(2);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(3);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(4);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(5);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(6);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(7);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(8);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(9);
DEFINE_CALLFUNC_AUTO_WITH_PARAM(10);
template <typename TRet>
static inline TRet callwiththis( void * pThis, void * pFunc ){
typedef TRet (nullclass::*funcptr)();
return (((nullclass*)pThis)->*p2t<funcptr>(pFunc))();
}
#define DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(paramcount) template <typename TRet, DP_STMP_##paramcount(typename, Tp)>\
static inline TRet callwiththis( void * pThis, void * pFunc, DP_MTMP_##paramcount(Tp, p ) ){\
typedef TRet (nullclass::*funcptr)(DP_MTMP_##paramcount(Tp, p ));\
return (((nullclass*)pThis)->*p2t<funcptr>(pFunc))(LP_SNMP_##paramcount( p ));\
}
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(1);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(2);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(3);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(4);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(5);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(6);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(7);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(8);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(9);
DEFINE_CALLFUNC_WITHTHIS_WITH_PARAM(10);
template <typename TRet>
static inline TRet callnothis( void * pFunc ){
typedef TRet (*funcptr)();
return (*p2t<funcptr>(pFunc))();
}
#define DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(paramcount) template <typename TRet, DP_STMP_##paramcount(typename, Tp)>\
static inline TRet callnothis( void * pFunc, DP_MTMP_##paramcount(Tp, p ) ){\
typedef TRet (*funcptr)(DP_MTMP_##paramcount(Tp, p ));\
return (*p2t<funcptr>(pFunc))(LP_SNMP_##paramcount( p ));\
}
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(1);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(2);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(3);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(4);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(5);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(6);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(7);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(8);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(9);
DEFINE_CALLFUNC_NOTHIS_WITH_PARAM(10);
};
這里面提供了三種調(diào)用方式, callauto 是根據(jù)this是否為NULL自動(dòng)選擇按照類成員函數(shù), 還是普通函數(shù) 來(lái)調(diào)用, callwiththis 固定按照類成員函數(shù)來(lái)調(diào)用, callnothis 固定按照非成員函數(shù)的方式來(lái)調(diào)用.
每種調(diào)用方式提供了10個(gè)帶參數(shù)的調(diào)用和1個(gè)不帶參數(shù)的調(diào)用. 最大支持 10個(gè)參數(shù)的成員函數(shù)調(diào)用, 基本上已經(jīng)足夠了.
這個(gè)struct的使用方法是
callfunction::callwiththis<returntype>( objectptr, memfuncptr, params ... );
比如我們要調(diào)用 類CAddObject 的對(duì)象指針 pObject 的返回類型為int 名字為 add, 并且?guī)в袃蓚€(gè)int型參數(shù)的成員函數(shù), 我們只需要這樣調(diào)用
int result = callfunction::callwiththis<int>( pObject, t2t<void*>( &CAddObject::add ), 20, 20 );
這樣,我們就調(diào)用了這個(gè)函數(shù),并且把結(jié)果保存在result
最后, 我們來(lái)封裝一個(gè)函數(shù)調(diào)用的對(duì)象, 用來(lái)更方便的使用這個(gè)方法
template <typename TRet>
class CCustomCall
{
typedef CCustomCall<TRet> TSelf;
void * lpThis;
void * lpFunc;
public:
CCustomCall( const TSelf & sv ):lpThis(sv.lpThis), lpFunc(sv.lpFunc) {}
template <typename TFunc>
CCustomCall( void * _this, TFunc _f ):lpThis(_this){
lpFunc = t2p<TFunc>( _f );
}
CCustomCall():lpThis(NULL), lpFunc(NULL){}
TSelf & operator =( const TSelf & sv )
{
lpThis = sv.lpThis;
lpFunc = sv.lpFunc;
return (*this);
}
#define DEFINE_CALL_WITH_PARAM(paramcount) template <DP_STMP_##paramcount( typename, Tp ) >\
TRet call( DP_MTMP_##paramcount(Tp, p ) ){\
return callfunction::callauto<TRet>( lpThis, lpFunc, LP_SNMP_##paramcount(p));\
}
DEFINE_CALL_WITH_PARAM(1);
DEFINE_CALL_WITH_PARAM(2);
DEFINE_CALL_WITH_PARAM(3);
DEFINE_CALL_WITH_PARAM(4);
DEFINE_CALL_WITH_PARAM(5);
DEFINE_CALL_WITH_PARAM(6);
DEFINE_CALL_WITH_PARAM(7);
DEFINE_CALL_WITH_PARAM(8);
DEFINE_CALL_WITH_PARAM(9);
DEFINE_CALL_WITH_PARAM(10);
TRet call(){return callfunction::callauto<TRet>( lpThis, lpFunc );}
bool empty(){ return (lpFunc == NULL);}
};
使用這個(gè)類, 就可以用簡(jiǎn)單的寫法來(lái)實(shí)現(xiàn)調(diào)用各種函數(shù)...
比如下面演示了使用同一個(gè)類來(lái)實(shí)現(xiàn)成員函數(shù)和非成員函數(shù)的混合調(diào)用.
typedef CCustomCall<int> IntCall;
class CTest
{
public:
int add( int n1, int n2 ){ return (n1+n2);}
int mul( int n1, int n2 ){ return (n1*n2);}
};
int div( int n1, int n2 ){ return (n1/n2);}
int main(int argc, char * argv[])
{
CTest test;
IntCall addcall( &test, &CTest::add );
IntCall mulcall( &test, &CTest::mul );
IntCall divcall( NULL, &div );
int nResult = 0;
nResult = addcall.call( 20, 20 );
printf( "addcall result = %d\n", nResult );
nResult = mulcall.call( 20, 20 );
printf( "mulcall result = %d\n", nResult );
nResult = divcall.call( 20, 20 );
printf( "divcall result = %d\n", nResult );
return 0;
}
輸出結(jié)果是
40
400
1
下面是一個(gè)作為事件調(diào)用的例子
typedef CCustomCall<void> EventCall;
class CButton
{
public:
EventCall eventOnClick;
};
class CApplication
{
.....
void OnOkButtonClick( CButton * pButton );
CButton m_OkButton;
};
............................初始化事件...............
BOOL CApplication::Init(){
.....
m_OkButton.eventOnClick = EventCall( this, &CApplication::OnOkButtonClick );
...
}
............................在BUTTON的鼠標(biāo)按下事件中.........................
void CButton::OnMouseDown( int key, int x, int y )
{
if( key == VK_LBUTTON && !eventOnClick.empty() )
eventOnClick.call( this ); /// 調(diào)用了設(shè)置的事件函數(shù), 在這個(gè)例子里, 當(dāng)this = CApplication::m_OkButton的時(shí)候, 就會(huì)調(diào)用 CApplication::OnOkButtonClick....
}