1.實現任意參數的函數委托
按上一篇文章的方法,你已經可以使用無參數的函數委托了。當然,這遠遠不夠。要實現任意參數的函數委托,這裡的任意參數包括任意個數和任意類型。任意類型這個容易解決,使用模板就行,但任意參數個數呢?
注:最終的實現代碼可以在這裡下載:http://www.BkJia.com/uploadfile/2011/1009/20111009023128248.rar
單參函數委托
template<typename TP1>
class CMultiDelegate1{};
// 雙參函數委托
template<typename TP1, typename TP2>
class CMultiDelegate2{};
// 單參函數委托
template<typename TP1>
class CMultiDelegate1{};
// 雙參函數委托
template<typename TP1, typename TP2>
class CMultiDelegate2{};
注意類名是不一樣的,分別為CMultiDelegate1和CMultiDelegate2
C++裡面,類名相同但模板參數個數不同是會當成一個類對待的,所以那樣編譯不過的
這樣是不是很麻煩呢?
不是很麻煩,是相當麻煩。因為不單單是CMultiDelegate要實現多個參數的版本
連IDelegate、CStaticDelegate和CMethodDelegate都要實現對應的多個參數的版本!
其實所有版本的內部實現幾乎一樣,下面給出雙參函數的版本
template<typename TP1, typename TP2>
class IDelegate2
{
public:
virtual ~IDelegate2() { }
virtual bool isType( const std::type_info& _type) = 0;
virtual void invoke( TP1 p1, TP2 p2 ) = 0;
virtual bool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const = 0;
};
template<typename TP1, typename TP2>
class CStaticDelegate2 : public IDelegate2<typename TP1, typename TP2>
{
public:
typedef void (*Func)( TP1 p1, TP2 p2 );
CStaticDelegate2 (Func _func) : mFunc(_func) { }
virtual bool isType( const std::type_info& _type) { return typeid( CStaticDelegate2<typename TP1, typename TP2> ) == _type; }
virtual void invoke( TP1 p1, TP2 p2 )
{
mFunc( p1, p2 );
}
virtual bool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const
{
if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate2 <typename TP1, typename TP2>)) ) return false;
CStaticDelegate2 <typename TP1, typename TP2> * cast = static_cast<CStaticDelegate2 <typename TP1, typename TP2> *>(_delegate);
return cast->mFunc == mFunc;
}
virtual bool compare(IDelegateUnlink * _unlink) const { return false; }
private:
Func mFunc;
};
template <typename T, typename TP1, typename TP2>
class CMethodDelegate2 : public IDelegate2 <typename TP1, typename TP2>
{
public:
typedef void (T::*Method)( TP1 p1, TP2 p2 );
CMethodDelegate2(T * _object, Method _method) : mObject(_object), mMethod(_method) { }
virtual bool isType( const std::type_info& _type) { return typeid( CMethodDelegate2 <T, TP1, TP2> ) == _type; }
virtual void invoke( TP1 p1, TP2 p2 )
{
(mObject->*mMethod)( p1, p2 );
}
virtual bool compare( IDelegate2 <typename TP1, typename TP2> * _delegate) const
{
if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate2 <T, TP1, TP2>)) ) return false;
CMethodDelegate2 <T, TP1, TP2> * cast = static_cast< CMethodDelegate2 <T, TP1, TP2> * >(_delegate);
return cast->mObject == mObject && cast->mMethod == mMethod;
}
private:
T * mObject;
Method mMethod;
};
template <typename TP1, typename TP2>
inline delegates::IDelegate2 <typename TP1, typename TP2> * newDelegate( void (*_func)( TP1 p1, TP2 p2 ) )
{
return new delegates::CStaticDelegate2 <typename TP1, typename TP2> (_func);
}
template <typename T, typename TP1, typename TP2>
inline delegates::IDelegate2 <typename TP1, typename TP2> * newDelegate( T * _object, void (T::*_method)( TP1 p1, TP2 p2 ) )
{
return new delegates::CMethodDelegate2 <T, TP1, TP2> (_object, _method);
}
template <typename TP1, typename TP2>
class CMultiDelegate2
{
public:
typedef IDelegate2 <typename TP1, typename TP2> IDelegate;
typedef typename std::list<IDelegate*> ListDelegate;
typedef typename ListDelegate::iterator ListDelegateIterator;
typedef typename ListDelegate::const_iterator ConstListDelegateIterator;
CMultiDelegate2 () { }
~CMultiDelegate2 () { clear(); }
bool empty() const
{
for (ConstListDelegateIterator iter = mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if (*iter) return false;
}
return true;
}
void clear()
{
for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if (*iter)
{
delete (*iter);
(*iter) = 0;
}
}
}
CMultiDelegate2 <typename TP1, typename TP2> & operator+=(IDelegate* _delegate)
{
for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if ((*iter) && (*iter)->compare(_delegate))
{
delete _delegate;
return *this;
//MYGUI_ASSERT(false, "dublicate delegate");
}
}
mListDelegates.push_back(_delegate);
return *this;
}
CMultiDelegate2 <typename TP1, typename TP2> & operator-=(IDelegate* _delegate)
{
for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if ((*iter) && (*iter)->compare(_delegate))
{
if ((*iter) != _delegate) delete (*iter);
(*iter) = 0;
break;
}
}
delete _delegate;
return *this;
}
void operator()( TP1 p1, TP2 p2 )
{
ListDelegateIterator iter = mListDelegates.begin();
while (iter != mListDelegates.end())
{
if (0 == (*iter))
{
iter = mListDelegates.erase(iter);
}
else
{
(*iter)->invoke( p1, p2 );
++iter;
}
}
}
private:
CMultiDelegate2 (const CMultiDelegate2 <typename TP1, typename TP2> & _event);
CMultiDelegate2<typename TP1, typename TP2> & operator=(const CMultiDelegate2<typename TP1, typename TP2> & _event);
private:
ListDelegate mListDelegates;
};
template<typename TP1, typename TP2>
class IDelegate2
{
public:
virtual ~IDelegate2() { }
virtual bool isType( const std::type_info& _type) = 0;
virtual void invoke( TP1 p1, TP2 p2 ) = 0;
virtual bool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const = 0;
};
template<typename TP1, typename TP2>
class CStaticDelegate2 : public IDelegate2<typename TP1, typename TP2>
{
public:
typedef void (*Func)( TP1 p1, TP2 p2 );
CStaticDelegate2 (Func _func) : mFunc(_func) { }
virtual bool isType( const std::type_info& _type) { return typeid( CStaticDelegate2<typename TP1, typename TP2> ) == _type; }
virtual void invoke( TP1 p1, TP2 p2 )
{
mFunc( p1, p2 );
}
virtual bool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const
{
if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate2 <typename TP1, typename TP2>)) ) return false;
CStaticDelegate2 <typename TP1, typename TP2> * cast = static_cast<CStaticDelegate2 <typename TP1, typename TP2> *>(_delegate);
return cast->mFunc == mFunc;
}
virtual bool compare(IDelegateUnlink * _unlink) const { return false; }
private:
Func mFunc;
};
template <typename T, typename TP1, typename TP2>
class CMethodDelegate2 : public IDelegate2 <typename TP1, typename TP2>
{
public:
typedef void (T::*Method)( TP1 p1, TP2 p2 );
CMethodDelegate2(T * _object, Method _method) : mObject(_object), mMethod(_method) { }
virtual bool isType( const std::type_info& _type) { return typeid( CMethodDelegate2 <T, TP1, TP2> ) == _type; }
virtual void invoke( TP1 p1, TP2 p2 )
{
(mObject->*mMethod)( p1, p2 );
}
virtual bool compare( IDelegate2 <typename TP1, typename TP2> * _delegate) const
{
if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate2 <T, TP1, TP2>)) ) return false;
CMethodDelegate2 <T, TP1, TP2> * cast = static_cast< CMethodDelegate2 <T, TP1, TP2> * >(_delegate);
return cast->mObject == mObject && cast->mMethod == mMethod;
}
private:
T * mObject;
Method mMethod;
};
template <typename TP1, typename TP2>
inline delegates::IDelegate2 <typename TP1, typename TP2> * newDelegate( void (*_func)( TP1 p1, TP2 p2 ) )
{
return new delegates::CStaticDelegate2 <typename TP1, typename TP2> (_func);
}
template <typename T, typename TP1, typename TP2>
inline delegates::IDelegate2 <typename TP1, typename TP2> * newDelegate( T * _object, void (T::*_method)( TP1 p1, TP2 p2 ) )
{
return new delegates::CMethodDelegate2 <T, TP1, TP2> (_object, _method);
}
template <typename TP1, typename TP2>
class CMultiDelegate2
{
public:
typedef IDelegate2 <typename TP1, typename TP2> IDelegate;
typedef typename std::list<IDelegate*> ListDelegate;
typedef typename ListDelegate::iterator ListDelegateIterator;
typedef typename ListDelegate::const_iterator ConstListDelegateIterator;
CMultiDelegate2 () { }
~CMultiDelegate2 () { clear(); }
bool empty() const
{
for (ConstListDelegateIterator iter = mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if (*iter) return false;
}
return true;
}
void clear()
{
for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if (*iter)
{
delete (*iter);
(*iter) = 0;
}
}
}
CMultiDelegate2 <typename TP1, typename TP2> & operator+=(IDelegate* _delegate)
{
for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if ((*iter) && (*iter)->compare(_delegate))
{
delete _delegate;
return *this;
//MYGUI_ASSERT(false, "dublicate delegate");
}
}
mListDelegates.push_back(_delegate);
return *this;
}
CMultiDelegate2 <typename TP1, typename TP2> & operator-=(IDelegate* _delegate)
{
for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)
{
if ((*iter) && (*iter)->compare(_delegate))
{
if ((*iter) != _delegate) delete (*iter);
(*iter) = 0;
break;
}
}
delete _delegate;
return *this;
}
void operator()( TP1 p1, TP2 p2 )
{
ListDelegateIterator iter = mListDelegates.begin();
while (iter != mListDelegates.end())
{
if (0 == (*iter))
{
iter = mListDelegates.erase(iter);
}
else
{
(*iter)->invoke( p1, p2 );
++iter;
}
}
}
private:
CMultiDelegate2 (const CMultiDelegate2 <typename TP1, typename TP2> & _event);
CMultiDelegate2<typename TP1, typename TP2> & operator=(const CMultiDelegate2<typename TP1, typename TP2> & _event);
private:
ListDelegate mListDelegates;
};
當然放心啦,不會讓大家將不同參數的版本各寫一遍的
下面要介紹的是MyGUI的解決方法,一個利用預編譯和頭文件重復編譯的方法(很有意思的)
我們一般寫頭文件時,都會加上防止頭文件重復編譯的代碼,如
www.2cto.com
#ifndef __XXX_H__
#define __XXX_H__
// ..類聲明等
#endif
#ifndef __XXX_H__
#define __XXX_H__
// ..類聲明等
#endif
這裡我們就要反其道而行,去掉防止重復編譯的代碼,然後重復包含這個頭文件,但每次其編譯的都是不同參數個數的版本
第一次編譯的是無參的,第二次是單參的,第三次是雙參.....一直到你想要支持的參數個數
那怎麼讓其每次編譯的都不同呢?
答案就是使用強大的預編譯:宏
下面給出單參的IDelegate的例子
首先定義以下宏:
copy to clipboardprint?#define DELEGATE_TEMPLATE template
#define DELEGATE_TEMPLATE_PARAMS <typename TP1>
#define DELEGATE_TEMPLATE_ARGS TP1 p1
#define MYGUI_I_DELEGATE IDelegate1
#define DELEGATE_TEMPLATE template
#define DELEGATE_TEMPLATE_PARAMS <typename TP1>
#define DELEGATE_TEMPLATE_ARGS TP1 p1
#define MYGUI_I_DELEGATE IDelegate1
那麼下面這段代碼就會編譯出單參的IDelegate版本
copy to clipboardprint?DELEGATE_TEMPLATE DELEGATE_TEMPLATE_PARAMS
class MYGUI_I_DELEGATE
{
public:
virtual ~MYGUI_I_DELEGATE() { }
virtual bool isType( const std::type_info& _type) = 0;
virtual void invoke( DELEGATE_PARAMS ) = 0;
virtual bool compare( MYGUI_I_DELEGATE DELEGATE_TEMPLATE_ARGS * _delegate) const = 0;
};
DELEGATE_TEMPLATE DELEGATE_TEMPLATE_PARAMS
class MYGUI_I_DELEGATE
{
public:
virtual ~MYGUI_I_DELEGATE() { }
virtual bool isType( const std::type_info& _type) = 0;
virtual void invoke( DELEGATE_PARAMS ) = 0;
virtual bool compare( MYGUI_I_DELEGATE DELEGATE_TEMPLATE_ARGS * _delegate) const = 0;
};
神奇吧,這裡使用的可以說是宏實現的多態。
在這段代碼編譯完了之後,將所有宏都undefine掉,如
copy to clipboardprint?#undef DELEGATE_TEMPLATE
#undef DELEGATE_TEMPLATE_PARAMS
#undef DELEGATE_TEMPLATE_ARGS
#undef MYGUI_I_DELEGATE
#undef DELEGATE_TEMPLATE
#undef DELEGATE_TEMPLATE_PARAMS
#undef DELEGATE_TEMPLATE_ARGS
#undef MYGUI_I_DELEGATE
再重新定義雙參版本的,如
copy to clipboardprint?#define DELEGATE_TEMPLATE template
#define DELEGATE_TEMPLATE_PARAMS <typename TP1, typename TP2>
#define DELEGATE_TEMPLATE_ARGS TP1 p1, TP2 p2
#define MYGUI_I_DELEGATE IDelegate2
#define DELEGATE_TEMPLATE template
#define DELEGATE_TEMPLATE_PARAMS <typename TP1, typename TP2>
#define DELEGATE_TEMPLATE_ARGS TP1 p1, TP2 p2
#define MYGUI_I_DELEGATE IDelegate2
那麼編譯出來的就是雙參的版本了!
使用這種方法就可以將其他的如CStaticDelegate、CMethodDelegate和CMultiDelegate的各種版本都實現了,
而你要做的僅是重新define下那些宏就行了,夠方便了吧。
下一篇文章將會介紹MyGUI實現的一些輔助類,如單委托和DelegateUnlink。並給出一個測試例子,測試該委托機制對C++各種函數的支持。
摘自:gouki04的專欄