VC6下如何实现通过字符串创建对象

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在编程过程中,有可能遇到想根据传入的字符串创建相应的对象,在VC7下可以实现,VC6下MFC没有实现该功能。

大家首先要明白,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(W2A(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 = W2A_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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航