wxWidgets和MFC动态类型信息比较

来源:互联网 发布:手机五级网络 编辑:程序博客网 时间:2024/05/23 00:27

 

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

  

 

本文适用于

wxWidgets-2.8.8

vs2005

 

欢迎转载,但请保留作者信息

 

wxWidgets被设计为支持动态类型信息。这个支持由wxObject实现,看看:

class WXDLLIMPEXP_BASE wxObject

{

    DECLARE_ABSTRACT_CLASS(wxObject)

……………….

public:

    bool IsKindOf(wxClassInfo *info) const;

………………

};

在这里DECLARE_ABSTRACT_CLASS定义为:

#define DECLARE_ABSTRACT_CLASS(name)                                          /

    public:                                                                   /

        static wxClassInfo ms_classInfo;                                      /

        virtual wxClassInfo *GetClassInfo() const;

让人不由自主想起了CObjectCRuntimeClass

class AFX_NOVTABLE CObject

{

public:

     virtual CRuntimeClass* GetRuntimeClass() const;

…………………..

public:

     BOOL IsKindOf(const CRuntimeClass* pClass) const;

………………………………….

public:

     static const CRuntimeClass classCObject;

……………………………

};

可以认为它们都是同样的想法,都是用一个类来保存类型信息,只不过MFC使用的类(实际声明为struct)叫作CRuntimeClasswxWidgets把它叫做wxClassInfo而已。

1.1    储存的类型信息

同样地比较CRuntimeClasswxClassInfo,可以发现它们储存的类型信息也是几乎一致的:

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();

        }

………………………….

public:

    const wxChar            *m_className;

    int                      m_objectSize;

    wxObjectConstructorFn    m_objectConstructor;

    const wxClassInfo       *m_baseInfo1;

    const wxClassInfo       *m_baseInfo2;

    static wxClassInfo      *sm_first;

    wxClassInfo             *m_next;

    static wxHashTable      *sm_classTable;

……………………..

};

struct CRuntimeClass

{

// Attributes

     LPCSTR m_lpszClassName;

     int m_nObjectSize;

     UINT m_wSchema; // schema number of the loaded class

     CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class

     CRuntimeClass* m_pBaseClass;

…………………………

 

     // CRuntimeClass objects linked together in simple list

     CRuntimeClass* m_pNextClass;       // linked list of registered classes

     const AFX_CLASSINIT* m_pClassInit;

};

从上面列出的两个类可以发现几个不同:

1.              wxClassInfo通过类的构造函数来给wxObject::ms_classInfo这个静态变量赋值,而CRuntimeClass则通过结构体的赋值来构建CObject::classCObject

2.              wxWidgets中,每个类用来储存类型信息的静态变量名称都是一致的,都叫ms_classInfo,而MFC中,每个类储存类型信息的静态变量名称则是不一致的,如CObject中储存类型信息的变量名称为classCObject,而CcmdTarget中储存类型信息的变量名称则为classCCmdTarget

3.              CRuntimeClass中多了一个叫m_wSchema的整数变量,因为MFC被设计为支持序列化。

4.              wxClassInfo中用于指向基类的指针有两个m_baseInfo1m_baseInfo2,而CRuntimeClass则只有一个m_pBaseClass,莫非是wxWidgetsm_baseInfo2来支持多重继承?暂时不是很了解。

5.              CRuntimeClassm_pClassInitm_pfnCreateObject来支持动态创建,wxClassInfo则只使用了m_objectConstructor这个回调函数。

6.              wxClassInfo中多了一个指向类型信息链表头的指针sm_first

7.              wxClassInfo中多了个sm_classTable,从名字猜测似乎是wxWidgets使用哈希表来进行类的快速查找。

1.2    声明支持动态类型

MFC中,如果一个类想要支持动态类型信息,它必须在类的定义中加上DECLARE_DYNAMIC,相应地在类的实现文件中使用IMPLEMENT_DYNAMIC

DECLARE_DYNAMIC的定义为:

#define DECLARE_DYNAMIC(class_name) /

public: /

     static const CRuntimeClass class##class_name; /

     virtual CRuntimeClass* GetRuntimeClass() const; /

IMPLEMENT_DYNAMIC则定义为:

#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) /

     AFX_COMDAT const CRuntimeClass class_name::class##class_name = { /

         #class_name, sizeof(class class_name), wSchema, pfnNew, /

              RUNTIME_CLASS(base_class_name), NULL, class_init }; /

     CRuntimeClass* class_name::GetRuntimeClass() const /

         { return RUNTIME_CLASS(class_name); } /

 

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) /

     IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL, NULL)

就这样,子类保存了父类中表示类型信息的CRuntimeClass指针。

wxWidgets中,在类的声明中使用DECLARE_ABSTRACT_CLASS或者其它在此基础上扩展出来的宏来声明支持动态类型信息。

#define DECLARE_ABSTRACT_CLASS(name)                                          /

    public:                                                                   /

        static wxClassInfo ms_classInfo;                                      /

        virtual wxClassInfo *GetClassInfo() const;

然后使用wxIMPLEMENT_CLASS_COMMON或者在其基础上扩展的宏来给ms_classInfo赋值。

#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; }

由于在wxWidgets中是使用了wxClassInfo的构造函数来完成一些变量的赋值,而在此构造函数中调用了Register函数,下面再看看wxClassInfo::Register

// This function wasn't written to be reentrant but there is a possiblity of

// reentrance if something it does causes a shared lib to load and register

// classes. On Solaris this happens when the wxHashTable is newed, so the first

// part of the function has been modified to handle it, and a wxASSERT checks

// against reentrance in the remainder of the function.

 

void wxClassInfo::Register()

{

    if ( !sm_classTable )

    {

        wxHashTable *classTable = new wxHashTable(wxKEY_STRING);

 

        // check for reentrance

        if ( sm_classTable )

            delete classTable;

        else

            sm_classTable = classTable;

    }

 

    // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you

    // link any object module twice mistakenly, or link twice against wx shared

    // library) will break this function because it will enter an infinite loop

    // and eventually die with "out of memory" - as this is quite hard to

    // detect if you're unaware of this, try to do some checks here.

    wxASSERT_MSG( sm_classTable->Get(m_className) == NULL,

        wxString::Format

        (

            _T("Class /"%s/" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"),

            m_className

        )

    );

 

    sm_classTable->Put(m_className, (wxObject *)this);

 

}

从这个函数可以看出,wxWidgets使用了一个哈希表来完成类名称和wxClassInfo指针之间的映射关系,这点是和MFC不同的,MFC仅仅是将需要动态创建的类的类型信息用单链表链接在一起,而wxWidgets则是将所有的类信息都放在了哈希表中。

至于其它的一些操作如判断子类和父类的关系等等则几乎是一样的,在此不做分析。

  

 

 

 

参考资料

打造windows下的嵌入式开发工具(6)wxWidgets-2.8.8(2008-9-4)

dll方式编译wxWidgets-2.8.8(2008-9-6)