MFC串行化原理
作者:flyfish 2014-2-8
简介
本文章源码分析MFC的版本是10.0(VC2010)
串行化Serialization简单说就是在程序中定义的对象转换成连续的字节数据,无论这种连续的字节数据是在内存还是存储在硬盘上。程序重启之后,读取硬盘的数据,可以根据硬盘上的数据生成一个新的对象。
数据的读写
CArchive类
串行化的前提
从获取的文件信息中生成一个的对象首先需要知道类的信息,知道类的信息以后还需要动态创建,所以串行化的前提就是
1运行时类型识别 RTTI 是RuntimeType Identification的缩写
2 动态创建
CRuntimeClass获取对象运行时类型信息和动态创建对象
对象的串行化示例代码
要使自己的类支持串行化功能时
首先创建一个继承自CObject 类
class CTest : public CObject
{
protected:
DECLARE_SERIAL(CTest);
public:
virtual void Serialize(CArchive& ar);
}
IMPLEMENT_SERIAL(CTest, CObject,0|VERSIONABLE_SCHEMA)
CObject ,CRuntimeClass, CArchive是MFC重要的三个类
CObject类的实现在文件objcore.cpp文件
CRuntimeClass结构和CArchive类的实现在arccore.cpp文件
CRuntimeClass类
动态创建 由CRuntimeClass的静态成员函数CreateObject提供,
存储类的信息包括类名,类的版本,类的继承关系等都是由CRuntimeClass实现的
该类位于afx.h文件中第422行的CRuntimeClass结构
struct CRuntimeClass
{
// Attributes
LPCSTRm_lpszClassName;
int m_nObjectSize;
UINTm_wSchema; // schema number of the loaded class
CObject*(PASCAL* m_pfnCreateObject)(); // NULL => abstractclass
#ifdef _AFXDLL
CRuntimeClass*(PASCAL* m_pfnGetBaseClass)();
#else
CRuntimeClass*m_pBaseClass;
#endif
// Operations
CObject*CreateObject();
BOOLIsDerivedFrom(const CRuntimeClass* pBaseClass) const;
// dynamic name lookup and creation
static CRuntimeClass* PASCAL FromName(LPCSTRlpszClassName);
static CRuntimeClass* PASCAL FromName(LPCWSTRlpszClassName);
static CObject* PASCAL CreateObject(LPCSTRlpszClassName);
static CObject* PASCAL CreateObject(LPCWSTRlpszClassName);
// Implementation
void Store(CArchive& ar) const;
static CRuntimeClass* PASCAL Load(CArchive& ar,UINT* pwSchemaNum);
// CRuntimeClass objects linked together in simple list
CRuntimeClass*m_pNextClass; // linked list of registered classes
const AFX_CLASSINIT* m_pClassInit;
};
CreateObject函数正是动态创建对象,因为该函数是全局使用所以使用了Static声明,
全局使用时语法是 类名::函数名(CreateObject)
两个CreateObject函数,一个处理多字节,一个处理Unicode
示例代码中使用的宏
DECLARE_SERIAL宏位于afx.h文件中的627行
#define DECLARE_SERIAL(class_name) …
IMPLEMENT_SERIAL宏 位于afx.h文件中的680行
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) …
正是DECLARE_SERIAL和IMPLEMENT_SERIAL这两个宏实现了动态创建对象
该宏封装了CRuntimeClass的CreateObject
整个CRuntimeClass对象构成了一简单的列表,指针都存储在m_classList中,该列表类是CTypedSimpleList
由m_pNextClass指针指向下一个CRuntimeClass结构
由m_pBaseClass指针确定类的继承关系
FromName函数就是一个遍历m_classList,进行字符串比较
CTypedSimpleList类位于afxtls_.h 79行
因为处理对象之前还要处理类版本号,类名长度等,所以CRuntimeClass 拥有Load函数和Store函数
void CRuntimeClass::Store(CArchive& ar) const
// stores a runtime class description
{
WORD nLen =(WORD)lstrlenA(m_lpszClassName);
ar <<(WORD)m_wSchema << nLen;
ar.Write(m_lpszClassName,nLen*sizeof(char));
}
CRuntimeClass* PASCALCRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)
// loads a runtime class description
{
代码位于arccore.cpp文件的183行
}
CArchive类
wSchema的作用区分类版本,通过CArchive读写对象。
GetObjectSchema是获取CRuntimeClass中类的wSchema版本信息
CArchive重载<<和>> 操作符读写各种类型的对象声明代码位于afx.h 1580行
CObject类
IsKindOf实现了类型识别功能
遍历列表中的元素与参数指定的某个CRuntimeClass对象比较,存在则返回TRUE
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
IsKindOf调用CRuntimeClass类的IsDerivedFrom函数
BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
{
代码位于objcore.cpp文件的165行
}
最终形成了如下宏
运行时类识别
DECLARE_DYNAMIC
IMPLEMENT_DYNAMIC
动态创建
DECLARE_DYNCREATE
IMPLEMENT_DYNCREATE
串行化
DECLARE_SERIAL
IMPLEMENT_SERIAL