![]() |
|
||||||||||||||
| | 首页 | 新闻 | 文库 | 方案 | 技术 | 独家 | 座谈 | 下载 | 图库 | 开发板 | 仿真器 | 邮购 | VIP会员 | 芯片代购 | 客户评价 | | ||
|
||
|
|||||
| wxWidgets和MFC动态类型信息比较 | |||||
作者:快乐虾 文章来源:http://blog.csdn.net/lights_joy 点击数: 更新时间:2008-9-8 ![]() |
|||||
|
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; 让人不由自主想起了CObject和CRuntimeClass: class AFX_NOVTABLE CObject { public: virtual CRuntimeClass* GetRuntimeClass() const; ………………….. public: BOOL IsKindOf(const CRuntimeClass* pClass) const; …………………………………. public: static const CRuntimeClass classCObject; …………………………… }; 可以认为它们都是同样的想法,都是用一个类来保存类型信息,只不过MFC使用的类(实际声明为struct)叫作CRuntimeClass而wxWidgets把它叫做wxClassInfo而已。 1.1 储存的类型信息同样地比较CRuntimeClass和wxClassInfo,可以发现它们储存的类型信息也是几乎一致的: 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_baseInfo1和m_baseInfo2,而CRuntimeClass则只有一个m_pBaseClass,莫非是wxWidgets用m_baseInfo2来支持多重继承?暂时不是很了解。 5. CRuntimeClass用m_pClassInit和m_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则是将所有的类信息都放在了哈希表中。 至于其它的一些操作如判断子类和父类的关系等等则几乎是一样的,在此不做分析。 |
|||||
| 文章录入:admin 责任编辑:admin | |||||
| 【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口】 | |||||
| 最新热点 | 最新推荐 | 相关文章 | ||
| 前置放大器在移动医疗服务系 便携式多通道大容量生理信号 防腐监测仪的设计与应用 基于AD1674的酶标仪的设计 基于C/S模式的JRTPLIB库的测 ffmpeg与jrtplib相结合应用 blackfin模拟摄像头驱动中的 可编程逻辑在数字信号处理系 发现VDSP4.5一个BUG:单步调 VDSP5.0双核工程下sml3中的变 |
| 网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!) |
| | 本站介绍 | 合作联络 | 欢迎投稿 | 广告业务 | 网站地图 | 设为首页 | 加入收藏 | 友情链接 | 网站公告 | 联系我们 | | |||
|