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

类别:编程语言 点击:0 评论:0 推荐:

在编程过程中,有可能遇到想根据传入的字符串创建相应的对象,在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

本文地址:http://com.8s8s.com/it/it25465.htm