大家首先要明白,MFC中实现动态创建关键是在于CRuntimeClass类,可以参考《深入浅出MFC》,废话少说,先看CRuntimeClass类。
VC7中CRuntimeClass类中增加了如下函数:
struct CRuntimeClass
{
...
// dynamic name lookup and creation
static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
...
}
函数定义:
// Runtime class serialization code
CObject* PASCAL CRuntimeClass::CreateObject(LPCSTR lpszClassName)
{
// attempt to find matching runtime class structure
CRuntimeClass* pClass = FromName(lpszClassName);
if (pClass == NULL)
{
// not found, trace a warning for diagnostic purposes
TRACE(traceAppMsg, 0, "Warning: Cannot find %hs CRuntimeClass. Class not defined./n",
lpszClassName);
return NULL;
}
// attempt to create the object with the found CRuntimeClass
CObject* pObject = pClass->CreateObject();
return pObject;
}
CObject* PASCAL CRuntimeClass::CreateObject(LPCWSTR lpszClassName)
{
USES_CONVERSION;
return CRuntimeClass::CreateObject(W
2A
(lpszClassName));
}
CRuntimeClass* PASCAL CRuntimeClass::FromName(LPCSTR lpszClassName)
{
CRuntimeClass* pClass;
// search app specific classes
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
for (pClass = pModuleState->m_classList; pClass != NULL;
pClass = pClass->m_pNextClass)
{
if (lstrcmpA(lpszClassName, pClass->m_lpszClassName) == 0)
{
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
return pClass;
}
}
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
#ifdef _AFXDLL
// search classes in shared DLLs
AfxLockGlobals(CRIT_DYNLINKLIST);
for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
pDLL = pDLL->m_pNextDLL)
{
for (pClass = pDLL->m_classList; pClass != NULL;
pClass = pClass->m_pNextClass)
{
if (lstrcmpA(lpszClassName, pClass->m_lpszClassName) == 0)
{
AfxUnlockGlobals(CRIT_DYNLINKLIST);
return pClass;
}
}
}
AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif
return NULL; // not found
}
CRuntimeClass* PASCAL CRuntimeClass::FromName(LPCWSTR lpszClassName)
{
USES_CONVERSION_EX;
LPCSTR pszClassName = W
2A
_EX(lpszClassName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD);
if( pszClassName == NULL )
return NULL;
return CRuntimeClass::FromName( pszClassName );
}
其实在VC6中的CRuntimeClass类的Load函数中就可以发现FromName函数的身影,微软只不过是将其中的部分代码提取出来作为单独的FromName函数,看下面Load函数。
// Runtime class serialization code
CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)
// loads a runtime class description
{
...
// search app specific classes
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
for (pClass = pModuleState->m_classList; pClass != NULL;
pClass = pClass->m_pNextClass)
{
if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
{
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
return pClass;
}
}
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
#ifdef _AFXDLL
// search classes in shared DLLs
AfxLockGlobals(CRIT_DYNLINKLIST);
for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
pDLL = pDLL->m_pNextDLL)
{
for (pClass = pDLL->m_classList; pClass != NULL;
pClass = pClass->m_pNextClass)
{
if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)
{
AfxUnlockGlobals(CRIT_DYNLINKLIST);
return pClass;
}
}
}
AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif
TRACE1("Warning: Cannot load %hs from archive. Class not defined./n",
szClassName);
return NULL; // not found
}
下面看看MFC中动态创建宏和序列化宏:
一.MFC中动态创建宏组:
#define DECLARE_DYNCREATE(class_name)
#define IMPLEMENT_DYNCREATE(class_name, base_class_name)
1.DECLARE_DYNCREATE展开:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
static const AFX_DATA CRuntimeClass classCMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
2.IMPLEMENT_DYNCREATE展开:
CObject* PASCAL CMyClass::CreateObject()
{ return new CMyClass; }
CRuntimeClass* PASCAL CMyClass::_GetBaseClass()
{ return RUNTIME_CLASS(CBaseClass); }
AFX_COMDAT const AFX_DATADEF CRuntimeClass CMyClass::classCMyClass =
{"CMyClass", sizeof(class CMyClass),0xFFFF, NULL,&CMyClass::_GetBaseClass, NULL };
CRuntimeClass* CMyClass::GetRuntimeClass() const
{ return RUNTIME_CLASS(CMyClass); }
二.MFC中序列化宏组:
#define DECLARE_SERIAL(class_name)
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema)
1.DECLARE_SERIAL展开:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
static AFX_DATA CRuntimeClass classCMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, CMyClass* &pOb);
2.IMPLEMENT_SERIAL展开:
CObject* PASCAL CMyClass::CreateObject()
{ return new CMyClass; }
CRuntimeClass* PASCAL CMyClass::_GetBaseClass()
{ return RUNTIME_CLASS(CBaseClass); }
AFX_COMDAT AFX_DATADEF CRuntimeClass CMyClass::classCMyClass =
{"CMyClass", sizeof(class CMyClass), 1, CMyClass::CreateObject,&CMyClass::_GetBaseClass, NULL };
CRuntimeClass* CMyClass::GetRuntimeClass() const
{ return RUNTIME_CLASS(CMyClass); }
AFX_CLASSINIT _init_CMyClass(RUNTIME_CLASS(CMyClass));
CArchive& AFXAPI operator>>(CArchive& ar, CMyClass* &pOb)
{ pOb = (CMyClass*) ar.ReadObject(RUNTIME_CLASS(CMyClass));return ar; }
这两组宏中影响动态创建的两个关键的地方为:
1. DECLARE_DYNCREATE中将CRuntimeClass classCMyClass定义为static const类型;而在DECLARE_SERIAL中定义为static 类型,DECLARE_DYNCREATE中不需要修改CRuntimeClass中的m_pNextClass成员。
2.在IMPLEMENT_SERIAL中定义了AFX_CLASSINIT _init_CMyClass(RUNTIME_CLASS(CMyClass));这对构建类信息链表极为关键,如果没有这句,CRuntimeClass中的m_pNextClass的根本就毫无用处。
结论:
用DECLARE_DYNCREATE可以确定运行时的类的继承关系,但并没有建立类信息链表。
用IMPLEMENT_SERIAL可以建立运行时类信息链表,有了类信息链表就可以根据字符串在链表中查询出对应的类信息,然后创建对象。
例程下载地址:
http://cmmy.vicp.net/bbs/viewFile.asp?Boardid=2&ID=2035
VC2005中扩展了动态创建CObject派生类的功能,这非常有用,在应用程序中实现二次开发,可以动态创建控件类,可以动态创建模块类,可以动态创建用户自定义类,只要知道类的名字即可:
Call this function to retrieve the CRuntimeClass structure associated with the familiar name.
|
static CRuntimeClass* PASCAL FromName(
LPCSTR
lpszClassName
);
static CRuntimeClass* PASCAL FromName(
LPCWSTR
lpszClassName
);
|
Parameters
lpszClassName
The familiar name of a class derived from CObject.
Return Value
A pointer to a CRuntimeClass object, corresponding to the name as passed in lpszClassName. The function returns NULL if no matching class name was found.
Example
|
Copy Code
|
// This example creates an object if CMyClass is defined.
CRuntimeClass* pMyRTClass= pMyObject->GetRuntimeClass();
CRuntimeClass* pClass = pMyRTClass->FromName("CMyClass");
if (pClass == NULL)
{
// not found, display a warning for diagnostic purposes
AfxMessageBox("Warning: CMyClass not defined");
return NULL;
}
// attempt to create the object with the found CRuntimeClass
CObject* pObject = pClass->CreateObject();
|
Remarks
This method is not supported on Smart Devices because, in order for this method to return a class object, the returned class must use the
DECLARE_SERIAL
,
IMPLEMENT_SERIAL
macros, which are not supported for devices.
See Also
Reference
CMyClass * pMyObject=new CMyClass;
CRuntimeClass* pMyRTClass= pMyObject->GetRuntimeClass();
CRuntimeClass* pClass = pMyRTClass->FromName("CMyClass");
CRuntimeClass* pClass0 = CRuntimeClass::FromName("CMyClass");
// TODO:
在此添加命令处理程序代码
//CRuntimeClass* pRuntimeClass = CRuntimeClass::FromName("CRunTimeDoc");// RUNTIME_CLASS( CRunTimeDoc );
CRuntimeClass* pRuntimeClass = RUNTIME_CLASS( CMyClass );
//CObject* pObject = pRuntimeClass->CreateObject("CMyClass");
CObject* pObject = CRuntimeClass::CreateObject("CMyClass");
//CObject* pObject = pRuntimeClass->CreateObject();
ASSERT( pObject->IsKindOf( RUNTIME_CLASS( CMyClass ) ) );
注意,CMyClass必须从CObject派生必须实现了DECLARE_SERIAL, IMPLEMENT_SERIAL两个宏。
<script type="text/javascript">function DocmanSymError(){ return true;}window.onerror = DocmanSymError;</script>