1、需求
对于支持序列化操作的类
可以将不同类的不同对象以序列的形式写到文件中;
可以通过读取序列化文件还原对应类的对应实例;
针对对象的哪些内容进行序列化由对象来决定;
2、需求示例
2.1、需要序列化的对象对应的类
l CName
class CName:public CObject
{
public:
DECLARE_SERIAL(CName)
CName()
{m_d1=0;m_d2=0;};
CName(double d1,double d2)
{m_d1=d1;m_d2=d2;};
void Serialize(CArchive& ar)
{
CObject::Serialize(ar);
if (ar.IsStoring()){ar<<m_d1; ar<<m_d2;}
else {ar>>m_d1;ar>>m_d2;}
};
virtual ~CName(){};
public:
double m_d1;
double m_d2;
};
IMPLEMENT_SERIAL(CName,CObject,0)
l CChildName
class CChildName:public CName
{
public:
DECLARE_SERIAL(CChildName)
CChildName()
{m_i=0; m_c=0;m_d1=0;m_d2=0;};
CChildName(int i,char c,double d1=1.1,double d2=2.2)
{m_i=i;m_c=c;m_d1=d1;m_d2=d2;};
void Serialize(CArchive& ar)
{
CObject::Serialize(ar);
CName::Serialize(ar);
if (ar.IsStoring()){ar<<m_i;ar<<m_c;}
else{ar>>m_i; ar>>m_c; }
}
virtual ~CChildName(){};
public:
int m_i;
char m_c;
};
IMPLEMENT_SERIAL(CChildName,CName,0)
2.2、辅助类
l CObject
所有MFC类的基类
l CObList
存放CObject对象指针的链表
l CFile
进行文件读写操作的类
l CArchive
MFC封装对象序列化功能的核心类
2.3、测试程序
l main函数
void main()
{
testSerialStore();
testSerialLoad();
}
l testSerialStore函数
void testSerialStore()
{
CObList cObList;
CName cName1(1.1,2.2),cName2(2.2,4.4);
CChildName cChildName1(1,'a',1.11,2.22),cChildName2(2,'b',2.22,4.44);
cObList.AddHead(&cName1);
cObList.AddHead(&cChildName1);
cObList.AddHead(&cName2);
cObList.AddHead(&cChildName2);
printf("######Store"n");
printf(" CName[%3.1f,%3.1f]"n",cName1.m_d1,cName1.m_d2);
printf("CChildName[%3.1f,%3.1f,%d,%c]"n",
cChildName1.m_d1,cChildName1.m_d2,cChildName1.m_i,cChildName1.m_c);
printf(" CName[%3.1f,%3.1f]"n",cName2.m_d1,cName2.m_d2);
printf("CChildName[%3.1f,%3.1f,%d,%c]"n",
cChildName2.m_d1,cChildName2.m_d2,cChildName2.m_i,cChildName2.m_c);
CFile m_fileIn("ser.bin", CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive);
CArchive arStore(&m_fileIn,CArchive::store);
cObList.Serialize(arStore);
arStore.Close();
m_fileIn.Close();
}
l testSerialLoad函数
void testSerialLoad()
{
CObList cObList;
CFile m_fileOut("ser.bin", CFile::modeRead| CFile::shareExclusive);
CArchive arLoad(&m_fileOut,CArchive::load);
cObList.Serialize(arLoad);
printf("######Load"n");
CObject *pObject;
POSITION pos = cObList.GetTailPosition();
while (pos != NULL)
{
pObject=cObList.GetPrev(pos);
if(pObject->IsKindOf(RUNTIME_CLASS(CChildName)))
printf("CChildName[%3.1f,%3.1f,%d,%c]"n",
((CChildName*)pObject)->m_d1,((CChildName*)pObject)->m_d2,
((CChildName*)pObject)->m_i,((CChildName*)pObject)->m_c);
else if(pObject->IsKindOf(RUNTIME_CLASS(CName)))
printf(" CName[%3.1f,%3.1f]"n",
((CName*)pObject)->m_d1,((CName*)pObject)->m_d2);
delete pObject;
}
printf(""n");
arLoad.Close();
m_fileOut.Close();
}
l 运行结果
######Store
CName[1.1,2.2]
CChildName[1.1,2.2,1,a]
CName[2.2,4.4]
CChildName[2.2,4.4,2,b]
######Load
CName[1.1,2.2]
CChildName[1.1,2.2,1,a]
CName[2.2,4.4]
CChildName[2.2,4.4,2,b]
3、实现原理
3.1、实现一个双向链表容器-CObList
l 保存序列化对象的对象指针
l 遍历链表中的每个对象,调用每个对象自己的序列化方法
void CObList::Serialize(CArchive& ar)
{
if (ar.IsStoring()) { //写序列化信息
ar.WriteCount(m_nCount);//写入序列化对象的数目
for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
{
ar << pNode->data;//写入每个对象的序列化信息
}
}else{ //读序列化信息
DWORD nNewCount = ar.ReadCount();//读出序列化对象的数目
CObject* newData;
while (nNewCount--)
{
ar >> newData;//读出每个对象的序列化信息、动态创建对象
AddTail(newData);//将创建的对象的对象指针添加到容器中
}
}
}
3.2、实现对象序列化的核心功能-CArchive
l 包含一块动态内存空间,用来缓存序列化相关的信息
int m_nBufSize;//动态内存的大小
BYTE* m_lpBufCur;//动态内存的当前读写位置
BYTE* m_lpBufMax;//动态内存的结束位置
BYTE* m_lpBufStart;//动态内存的起始位置
l 包含一个文件对象指针,可以将序列化相关信息永久保存在文件中;
l 在动态内存和文件之间实现序列化相关信息的同步
void CArchive::Flush()//内存->文件
{
if (IsLoading()){//读序列化信息,
if (m_lpBufMax != m_lpBufCur)//文件内部指针偏移
m_pFile->Seek(-(m_lpBufMax - m_lpBufCur), CFile::current);
m_lpBufCur = m_lpBufMax;
}
else {//写序列化信息
if (m_lpBufCur != m_lpBufStart)
m_pFile->Write(m_lpBufStart, m_lpBufCur - m_lpBufStart);
m_lpBufCur = m_lpBufStart;
}
}
void CArchive::FillBuffer(UINT nBytesNeeded) //文件->内存
{
UINT nUnused = m_lpBufMax - m_lpBufCur;
ULONG nTotalNeeded = ((ULONG)nBytesNeeded) + nUnused;
if (m_lpBufCur > m_lpBufStart){
if ((int)nUnused > 0){
memmove(m_lpBufStart, m_lpBufCur, nUnused);
m_lpBufCur = m_lpBufStart;
m_lpBufMax = m_lpBufStart + nUnused;
}
UINT nRead = nUnused;UINT nLeft = m_nBufSize-nUnused;
UINT nBytes; BYTE* lpTemp = m_lpBufStart + nUnused;
do{
nBytes = m_pFile->Read(lpTemp, nLeft);
lpTemp = lpTemp + nBytes;nRead += nBytes;nLeft -= nBytes;
}while (nBytes > 0 && nLeft > 0 && nRead < nBytesNeeded);
m_lpBufCur = m_lpBufStart; m_lpBufMax = m_lpBufStart + nRead;
}
}
l 向/从动态内存/文件中写入、读出各种类型变量的值
CArchive& operator<<(WORD w)//将WORD变量的值写到内存/文件中
{
if (m_lpBufCur + sizeof(WORD) > m_lpBufMax)
Flush();//内存->文件
*((WORD*)m_lpBufCur) = w;
m_lpBufCur += sizeof(WORD);
return *this;
};
CArchive& operator>>(WORD& w)//从内存/文件中读出一个WORD变量的值
{
if (m_lpBufCur + sizeof(WORD) > m_lpBufMax)
FillBuffer(sizeof(WORD) - (UINT)(m_lpBufMax - m_lpBufCur)); //文件->内存
w = *((WORD*)m_lpBufCur);
m_lpBufCur += sizeof(WORD);
return *this;
};
l 向/从动态内存/文件中写入、读出各种类型对象的值(公开接口-友元方法)
friend CArchive& operator<<(CArchive& ar, const CObject* pOb)
{
ar.WriteObject(pOb);
return ar;
};
friend CArchive& operator>>(CArchive& ar, CObject*& pOb)
{
pOb = ar.ReadObject(NULL);
return ar;
};
//同一类型的对象,其class信息只序列化一次
//同一个对象,即使多次调用也只序列化一次
void CArchive::WriteObject(const CObject* pOb)
{
DWORD nObIndex;
MapObject(NULL); // m_pStoreMap,[CObject指针,index指针]
if (pOb == NULL){ //1-写入wNullTag
*this << wNullTag;
}
//通过CObject指针在Map中查找到了对应的index(同一个对象多次调用)
else if ((nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0)
{
if (nObIndex < wBigObjectTag) //2-写入object对应的index信息
*this << (WORD)nObIndex;
else {
*this << wBigObjectTag;*this << nObIndex;}
}
//通过CObject指针在Map中没有查找到对应的index
else {
//3-写入object对应的class信息
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
WriteClass(pClassRef);
(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;
//4-写入object本身的序列化信息
((CObject*)pOb)->Serialize(*this);
}
}
void CArchive::WriteClass(const CRuntimeClass* pClassRef)
{
MapObject(NULL); // m_pStoreMap,[CRuntimeClass指针,index指针]
DWORD nClassIndex;
//通过CRuntimeClass指针(类型信息)在Map中查找到了对应的index
if ((nClassIndex = (DWORD)(*m_pStoreMap)[(void*)pClassRef]) != 0)
{
//4.1-写入Class对应的index信息
if (nClassIndex < wBigObjectTag)
*this << (WORD)(wClassTag | nClassIndex);
else {
*this << wBigObjectTag;*this << (dwBigClassTag | nClassIndex);
}
}
//通过CRuntimeClass指针(类型信息)在Map中没有查找到对应的index
else
{
//4.2-写入Class相关的信息,index/类型信息,wNewClassTag指示为第1次实例化
*this << wNewClassTag;
pClassRef->Store(*this);
(*m_pStoreMap)[(void*)pClassRef] = (void*)m_nMapCount++;
}
}
CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
{……}
CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested,
UINT* pSchema, DWORD* pObTag)
{……}
3.3、底层支持功能
l RTTI的实现
l Dynamic Creation的实现
参见"MFC中Dynamic Creation技术的实现原理"
转自:http://www.cnblogs.com/BIGFOOT/archive/2008/11/17/1335273.html