您的位置:首页 > 其它

MFC中对象序列化技术的实现

2013-01-15 14:33 357 查看
MFC中对象序列化技术的实现

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的实现

参见"MFC中RTTI技术的实现原理"

l
Dynamic Creation的实现

参见"MFC中Dynamic Creation技术的实现原理"

转自:/article/7066152.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: