// 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鏈表。這一點和侯捷先生所述有點不同。