下载本文示例代码
一、概述 本文对MFC动态创建对象的方法做了一点阐述,给出了一些我认为存在的问题及相应的解决方法,不当及不足之处请各位不吝赐教。这里指的动态创建指给定一个类的名字(字符串),创建出相应的类的实例,类似于java里面的反射机制。 二、问题描述 对于给定的类,我们可以采取
CSampClass *m_pSampClass=new CSampClass 的方法,或稍微麻烦一点
CRuntimeClass *m_pRuntimeClass=RUNTIME_CLASS(CSampClass);m_pSampClass=(CSampClass *)m_pRuntimeClass->CreateObject(); 我想大家都会毫不犹豫的选择第一种方法,这里给出第二种方法,只是为了下面叙述的方便。 现在给定的是一个类名字符串"CSampClass",我们当然不能直接用CSampClass *m_pSampClass=new "CSampClass"的方法创建出对象来。同样第二种方法也不行,但它给我们提供了另外一种思路:利用MFC的动态创建机制。 根据动态创建机制,我们需要在我们的类中加入DECLARE_DYNACREATE和IMPLEMEN_DYNACREATE宏,这两个宏的作用是在我们的类中加入一个CRuntimeClass类型的静态成员变量,然后将其加入一张链表中,构成我们的运行时类别信息表,以支持类的RTTI、DYNACREATE以及SERILIZE。 现在来看看CRuntimeClass里面到底有些什么东西,以下是其结构,来自MSDN.
struct CRuntimeClass{ LPCSTR m_lpszClassName; int m_nObjectSize; UINT m_wSchema; CObject *(PASCAL *m_pfnCreateObject)(); CRuntimeClass *m_pBaseClass; CObject *CreateObject(); BOOL IsDerivedFrom(Const CRuntimeClass *pBaseClass) Const;} 其中,m_lpszClassName是对应的类名,m_pBaseClass是基类对应的CRuntimeClass结构,利用CreateObject我们就能够构建出对应类的实例来。 提到CRuntimeClass,我们不得不提到一个很重要的宏RUNTIME_CLASS,它接受一个类,并返回该类对应的CRuntimeClass结构,那么看到这里我们不难理解上面创建对象的 第二种方法,并且我们的动态创建好象也有了眉目:我们只需要遍历CRuntimeClass链表,把每个接点的m_lpszClassName和给定的类名字符串比较,如果相等,调用该接点的CreateObject()即可。 事情到此好象已经完了,真的那么简单吗? 我们再来检查一下,遍历链表,我们需要知道链表的头吧。头在哪里?RUNTIME_CLASS宏只是提供了我们给定的宏的CRuntimeClass结构,该结构并不是我们所要的头。并且CRuntimeClass结构也没为遍历整个链表提供足够的信息,m_pBaseClass只是为我们提供了按继承关系进行遍历的手段,但这无法支持对整个链表的遍历。好不容易走到这里,线索似乎又断了。 没办法,翻翻侯捷老师的深入浅出MFC吧。里面P97页讲到动态创建时,用到的CRuntimeClass结构如下:
struct CRuntimeClass{ LPCSTR m_lpszClassName; int m_nObjectSize; UINT m_wSchema; CObject *(PASCAL *m_pfnCreateObject)(); CRuntimeClass *m_pBaseClass; CObject *CreateObject(); BOOL IsDerivedFrom(Const CRuntimeClass *pBaseClass) Const; static CRuntimeClass *m_pFirstClass; CRuntimeClass *m_pNextClass;} 看到最后两个字段,我们不难推想出侯老师用的动态创建算法,不知道微软把这两个字段藏到什么地方去了。 后来看侯捷老师在深入浅出MFC中介绍SERILIZE时,在P388页有这么一段代码(我自己稍做改编,伪码),很给我启发:
CRuntimeClass *CRuntimeClass::Load(CString szClassName){ CRuntimeClass *pClass=NULL; AFX_MODULE_STATE pModuleState=afxGetModuleState(); ASSERT(!pModuleState->m_classList.IsEmpty()); //我加的断言,调试用 for (pClass=pModuleState->m_classList;pClass!=NULL;pClass=pClass->m_pNextClass) if (lstrcmpa(szClassName,pClass->m_lpszClassName)==0) return pClass; return NULL;} 这段代码好象是说所有的CRuntimeClass结构都放在pModuleState->m_classList,但我在调试是时断言总是不成立,并且pClass=pClass->m_pNextClass这一句也让我困惑不已,MFC里面的CRunTimeClass哪里来的m_pNextClass字段?请高手指点。 三、解决办法 既然在MFC里面好象直接找不到办法(也许是我暂时没发现,请高手指教),我们可以采用间接的办法,自己 写一个CRuntimeClassEX类,包装MFC里面的CRuntimeClass,另加两个字段:
struct CRuntimeClassEX{ CRuntimeClass *m_pCRunTimeClass; static CRuntimeClass *m_pFirstClass; CRuntimeClass *m_pNextClass; } 同样,需要包装DECLARE_DYNACREATE(DECLARE_DYNACREATEX)和IMPLEMEN_DYNACREATE(IMPLEMEN_DYNACREATEX)两个宏,具体请参见候捷老师在深入浅出MFC里面的方法。我们在动态创建时只需要遍历该链表,找到相应的CRuntimeClass,即可创建出我们的对象来。zmbbs=1;
一、概述 本文对MFC动态创建对象的方法做了一点阐述,给出了一些我认为存在的问题及相应的解决方法,不当及不足之处请各位不吝赐教。这里指的动态创建指给定一个类的名字(字符串),创建出相应的类的实例,类似于java里面的反射机制。 二、问题描述 对于给定的类,我们可以采取
CSampClass *m_pSampClass=new CSampClass 的方法,或稍微麻烦一点
CRuntimeClass *m_pRuntimeClass=RUNTIME_CLASS(CSampClass);m_pSampClass=(CSampClass *)m_pRuntimeClass->CreateObject(); 我想大家都会毫不犹豫的选择第一种方法,这里给出第二种方法,只是为了下面叙述的方便。 现在给定的是一个类名字符串"CSampClass",我们当然不能直接用CSampClass *m_pSampClass=new "CSampClass"的方法创建出对象来。同样第二种方法也不行,但它给我们提供了另外一种思路:利用MFC的动态创建机制。 根据动态创建机制,我们需要在我们的类中加入DECLARE_DYNACREATE和IMPLEMEN_DYNACREATE宏,这两个宏的作用是在我们的类中加入一个CRuntimeClass类型的静态成员变量,然后将其加入一张链表中,构成我们的运行时类别信息表,以支持类的RTTI、DYNACREATE以及SERILIZE。 现在来看看CRuntimeClass里面到底有些什么东西,以下是其结构,来自MSDN.
struct CRuntimeClass{ LPCSTR m_lpszClassName; int m_nObjectSize; UINT m_wSchema; CObject *(PASCAL *m_pfnCreateObject)(); CRuntimeClass *m_pBaseClass; CObject *CreateObject(); BOOL IsDerivedFrom(Const CRuntimeClass *pBaseClass) Const;} 其中,m_lpszClassName是对应的类名,m_pBaseClass是基类对应的CRuntimeClass结构,利用CreateObject我们就能够构建出对应类的实例来。 提到CRuntimeClass,我们不得不提到一个很重要的宏RUNTIME_CLASS,它接受一个类,并返回该类对应的CRuntimeClass结构,那么看到这里我们不难理解上面创建对象的 第二种方法,并且我们的动态创建好象也有了眉目:我们只需要遍历CRuntimeClass链表,把每个接点的m_lpszClassName和给定的类名字符串比较,如果相等,调用该接点的CreateObject()即可。 事情到此好象已经完了,真的那么简单吗? 我们再来检查一下,遍历链表,我们需要知道链表的头吧。头在哪里?RUNTIME_CLASS宏只是提供了我们给定的宏的CRuntimeClass结构,该结构并不是我们所要的头。并且CRuntimeClass结构也没为遍历整个链表提供足够的信息,m_pBaseClass只是为我们提供了按继承关系进行遍历的手段,但这无法支持对整个链表的遍历。好不容易走到这里,线索似乎又断了。 没办法,翻翻侯捷老师的深入浅出MFC吧。里面P97页讲到动态创建时,用到的CRuntimeClass结构如下:
struct CRuntimeClass{ LPCSTR m_lpszClassName; int m_nObjectSize; UINT m_wSchema; CObject *(PASCAL *m_pfnCreateObject)(); CRuntimeClass *m_pBaseClass; CObject *CreateObject(); BOOL IsDerivedFrom(Const CRuntimeClass *pBaseClass) Const; static CRuntimeClass *m_pFirstClass; CRuntimeClass *m_pNextClass;} 看到最后两个字段,我们不难推想出侯老师用的动态创建算法,不知道微软把这两个字段藏到什么地方去了。 后来看侯捷老师在深入浅出MFC中介绍SERILIZE时,在P388页有这么一段代码(我自己稍做改编,伪码),很给我启发:
CRuntimeClass *CRuntimeClass::Load(CString szClassName){ CRuntimeClass *pClass=NULL; AFX_MODULE_STATE pModuleState=afxGetModuleState(); ASSERT(!pModuleState->m_classList.IsEmpty()); //我加的断言,调试用 for (pClass=pModuleState->m_classList;pClass!=NULL;pClass=pClass->m_pNextClass) if (lstrcmpa(szClassName,pClass->m_lpszClassName)==0) return pClass; return NULL;} 这段代码好象是说所有的CRuntimeClass结构都放在pModuleState->m_classList,但我在调试是时断言总是不成立,并且pClass=pClass->m_pNextClass这一句也让我困惑不已,MFC里面的CRunTimeClass哪里来的m_pNextClass字段?请高手指点。 三、解决办法 既然在MFC里面好象直接找不到办法(也许是我暂时没发现,请高手指教),我们可以采用间接的办法,自己 写一个CRuntimeClassEX类,包装MFC里面的CRuntimeClass,另加两个字段:
struct CRuntimeClassEX{ CRuntimeClass *m_pCRunTimeClass; static CRuntimeClass *m_pFirstClass; CRuntimeClass *m_pNextClass; } 同样,需要包装DECLARE_DYNACREATE(DECLARE_DYNACREATEX)和IMPLEMEN_DYNACREATE(IMPLEMEN_DYNACREATEX)两个宏,具体请参见候捷老师在深入浅出MFC里面的方法。我们在动态创建时只需要遍历该链表,找到相应的CRuntimeClass,即可创建出我们的对象来。zmbbs=1;
下载本文示例代码
MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考MFC中动态创建对象的一点思考
阅读(204) | 评论(0) | 转发(0) |