// Runtime class serialization code
CRuntimeClass* PASCALCRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)
//loads a runtime class description
{
WORDnLen;//类名的长度
charszClassName[64];//存放类名的字符数组
CRuntimeClass*pClass;
WORDwTemp;
ar>> wTemp; *pwSchemaNum = wTemp;//加载版本号
ar>> nLen;//加载类名长度
if(nLen >= _countof(szClassName) ||
ar.Read(szClassName,nLen*sizeof(char)) != nLen*sizeof(char))//读取类名到数组
{
returnNULL;
}
szClassName[nLen]= '\0';//字符串末尾补零
//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);
returnpClass;
}
}
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
TRACE1("Warning:Cannot load %hs from archive. Class notdefined.\n",
szClassName);
returnNULL; // not found
}
注意:m_classList定义在类AFX_MODULE_STATE中
CTypedSimpleList<CRuntimeClass*>m_classList; 它是类别型录网链表的表头
struct CRuntimeClass
{
// Attributes
LPCSTRm_lpszClassName;
intm_nObjectSize;
UINTm_wSchema; // schema number of the loaded class
CObject*(PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass*m_pBaseClass;
// Operations
CObject*CreateObject();
BOOLIsDerivedFrom(const CRuntimeClass* pBaseClass) const;
// Implementation
voidStore(CArchive& ar) const;
staticCRuntimeClass* PASCAL Load(CArchive& ar,UINT* pwSchemaNum);
//CRuntimeClass objects linked together in simple list用简单链表链接起来
CRuntimeClass*m_pNextClass; // linked list ofregistered classes
};
void CRuntimeClass::Store(CArchive& ar)const
//stores a runtime class description
{
WORDnLen = (WORD)lstrlenA(m_lpszClassName);//得到类名的长度
ar<< (WORD)m_wSchema << nLen;//存档版本号和类名长度
ar.Write(m_lpszClassName,nLen*sizeof(char));//写入类名
}
总结:CRuntimeClass::Load函数首先加载版本号和类名长度,然后再利用加载的类名长度去加载出类名,利用此类名去检索类别型录网看其有否记录在案。
CRuntimeClass::Store只是简单地依次存储版本号、类名长度、类名到归档中。
#defineDECLARE_DYNAMIC(class_name) \
public: \
staticconst AFX_DATA CRuntimeClass class##class_name; \
virtualCRuntimeClass* GetRuntimeClass() const; \
// not serializable, but dynamicallyconstructable
#defineDECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name)\
staticCObject* PASCAL CreateObject();
#define DECLARE_SERIAL(class_name) \
_DECLARE_DYNCREATE(class_name)\
AFX_APIfriend CArchive& AFXAPI operator>>(CArchive& ar, class_name*&pOb);
// generate static object constructor forclass registration
void AFXAPI AfxClassInit(CRuntimeClass*pNewClass);
struct AFX_CLASSINIT
{AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
struct AFX_CLASSINIT_COMPAT
{AFX_CLASSINIT_COMPAT(CRuntimeClass* pNewClass); };
#define IMPLEMENT_RUNTIMECLASS(class_name,base_class_name, wSchema, pfnNew) \
AFX_COMDATconst AFX_DATADEF CRuntimeClass class_name::class##class_name = { \
#class_name,sizeof(class class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name),NULL }; \
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)
#define IMPLEMENT_DYNCREATE(class_name,base_class_name) \
CObject*PASCAL class_name::CreateObject() \
{return new class_name; } \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name,0xFFFF, \
class_name::CreateObject)
#define IMPLEMENT_SERIAL(class_name,base_class_name, wSchema) \
CObject*PASCAL class_name::CreateObject() \
{return new class_name; } \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name,wSchema, \
class_name::CreateObject)\
AFX_CLASSINIT_init_##class_name(RUNTIME_CLASS(class_name)); \
CArchive&AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
{pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
returnar; } \
// optional bit for schema number thatenables object versioning
#define VERSIONABLE_SCHEMA (0x80000000)
BOOL CRuntimeClass::IsDerivedFrom(constCRuntimeClass* pBaseClass) const
{
ASSERT(this!= NULL);
ASSERT(AfxIsValidAddress(this,sizeof(CRuntimeClass), FALSE));
ASSERT(pBaseClass!= NULL);
ASSERT(AfxIsValidAddress(pBaseClass,sizeof(CRuntimeClass), FALSE));
//simple SI case
constCRuntimeClass* pClassThis = this;
while(pClassThis != NULL)
{
if(pClassThis == pBaseClass)
returnTRUE;
#ifdef _AFXDLL
pClassThis= (*pClassThis->m_pfnGetBaseClass)();
#else
pClassThis= pClassThis->m_pBaseClass;//不断往基类上溯
#endif
}
returnFALSE; // walked to the top, nomatch
}
void AFXAPI AfxClassInit(CRuntimeClass*pNewClass)
{
AFX_MODULE_STATE*pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);//进入关键代码段
pModuleState->m_classList.AddHead(pNewClass);//将新结点加到表头后面
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
}
// generate static object constructor forclass registration
//为类的注册产生一个静态的对象构造函数
void AFXAPI AfxClassInit(CRuntimeClass*pNewClass);
struct AFX_CLASSINIT
{AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
由上面所述可知动态识别和动态创建都没产生RuntimeClas链表(没有用next指针连起来),而只有与父类的链表(用m_pBaseClass连起来)。只有序列化时,才有CRuntimeClass链表。这一点和侯捷先生所述有点不同。