[Effective WX] wx中的反射機制:DANYMIC_CLASS的實現

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是否是同一個,或者如果該請求類有基類的話,基類是否那個條件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章