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

参见"MFCRTTI技术的实现原理"

l         Dynamic Creation的实现

参见"MFCDynamic Creation技术的实现原理"

 

转自:http://www.cnblogs.com/BIGFOOT/archive/2008/11/17/1335273.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值