wx利用兩個宏實現了幾乎所有以wx開頭的窗口類的反射機制:
DECLARE_DYNAMIC_CLASS
IMPLEMENT_DYNAMIC_CLASS
當一個類想借助於wx實現的dynamic_class的機制,必須得繼承於wxObject或者是它的子類。有了這個前提條件之後,在你的類中,你只需要這樣操作:
1. 在類的聲明中,寫下:
DECLARE_DYNAMIC_CLASS($your_class_name);
2. 在類的實現文件中,寫下:
IMPLEMENT_DYNAMIC_CLASS($your_class_name, $base_class_from_wxObject);
那麼這2個宏到底幫我們做了些什麼事情呢,我們來展開那2個宏來看看:
首先是DECLARE_DYNAMIC_CLASS($your_class_name)
#define DECLARE_ABSTRACT_CLASS (name) \
public: \
static wxClassInfo ms_classInfo; \
virtual wxClassInfo *GetClassInfo() const;
#define DECLARE_DYNAMIC_CLASS (name) \
DECLARE_ABSTRACT_CLASS(name ) \
static wxObject * wxCreateObject();
如果你的類不是抽象類,請用DECLARE_DYNAMIC_CLASS,否則就用DECLARE_ABSTRACT_CLASS。區別在於抽象類是無法實例化的,也就沒辦法提供對象構造器。我們具體來看下DECLARE_ABSTRACT_CLASS這個宏。
這個宏主要是幫助提供了一個類wxClassInfo的靜態變量,用來存儲這個類的信息,同時也提供了訪問給外界這個靜態變量的接口。
所以總體來說,DECLEAR_*宏是在我們類中添加了額外的用來存儲類相關信息的一個靜態變量。有了這個靜態變量,外界就可以通過Get接口來獲取它的相關信息。
下面來看看IMPLEMENT_DYNAMIC_CLASS宏。
#define wxIMPLEMENT_CLASS_COMMON (name, basename, baseclsinfo2, func ) \
wxClassInfo name ::ms_classInfo( wxT(#name ), \
& basename::ms_classInfo , \
baseclsinfo2, \
( int) sizeof (name), \
( wxObjectConstructorFn) func ); \
\
wxClassInfo *name ::GetClassInfo() const \
{ return &name ::ms_classInfo; }
#define wxIMPLEMENT_CLASS_COMMON1 (name, basename, func) \
wxIMPLEMENT_CLASS_COMMON(name , basename, NULL, func)
#define IMPLEMENT_DYNAMIC_CLASS (name, basename) \
wxIMPLEMENT_CLASS_COMMON1(name , basename, name::wxCreateObject ) \
wxObject* name ::wxCreateObject() \
{ return new name; }
wx中最多隻能讓一個dynamic繼承於2個wxObject子類,應該是虛繼承。所以wxIMPLEMENT_CLASS_COMMON只提供了2個basename接口。
從展開的宏來看,它主要做的事情就是初始化我們類的靜態變量(ms_classInfo),初始化時,傳入的動態對象構造器就是wxCreateObject(簡單的調用new操作符)。
所以下面我們來看下wxClassInfo類。
typedef wxObject *(*wxObjectConstructorFn)( void);
class WXDLLIMPEXP_BASE wxClassInfo
{
public:
wxClassInfo( const wxChar * className,
const wxClassInfo *baseInfo1,
const wxClassInfo *baseInfo2,
int size ,
wxObjectConstructorFn ctor )
: m_className(className )
, m_objectSize(size )
, m_objectConstructor(ctor )
, m_baseInfo1(baseInfo1 )
, m_baseInfo2(baseInfo2 )
, m_next(sm_first )
{
sm_first = this ;
Register();
}
static wxHashTable *sm_classTable;
...
void wxClassInfo ::Register()
{
if ( !sm_classTable )
{
wxHashTable *classTable = new wxHashTable(wxKEY_STRING );
// check for reentrance
if ( sm_classTable )
delete classTable ;
else
sm_classTable = classTable ;
}
sm_classTable->Put (m_className, ( wxObject *)this );
}
這個類的構造函數僅僅是將類和它類名註冊到一個hash table中,這個hash table是以類名爲字符串作爲key.
以上是C++中反射機制的比較典型的實現方式。
wx提供了下面2個宏操作:
#define wxIS_KIND_OF (obj, className) obj->IsKindOf (&className:: ms_classInfo)
// Just seems a bit nicer-looking (pretend it's not a macro)
#define wxIsKindOf (obj, className) obj->IsKindOf (&className:: ms_classInfo)
判斷某個類的對象,是否屬於某個class,這種屬於應該是按照類的繼承數來搜索的,滿足"IS-A"關係。
有了wx那樣實現機制,我們可以通過className可以很容器的查找到關存在它內部的classInfo變量。
IsKindOf函數定義在wxObject內部,要知道wxObject也是添加了DECLEAR*宏的:
DECLARE_ABSTRACT_CLASS (wxObject)
所以自然也有wxClassInfo信息。這個IsKindOf轉調用wxClassInfo::IsKindOf。
bool wxObject ::IsKindOf( wxClassInfo *info ) const
{
wxClassInfo *thisInfo = GetClassInfo();
return (thisInfo ) ? thisInfo-> IsKindOf(info ) : false ;
}
bool wxClassInfo::IsKindOf(const wxClassInfo *info ) const
{
return info != 0 &&
( info == this ||
( m_baseInfo1 && m_baseInfo1 ->IsKindOf( info) ) ||
( m_baseInfo2 && m_baseInfo2 ->IsKindOf( info) ) );
}
所以它做的事情很簡單,就是判斷它們的wxClassInfo是否是同一個,或者如果該請求類有基類的話,基類是否那個條件。