MFC六大机制(六)序列化机制

来源:互联网 发布:玛雅数据 编辑:程序博客网 时间:2024/06/14 08:31

一、对象的序列化

1、概念

序列化对象 - 将对象的类信息和对象的成员变量依次写入到文件的过程。

反序列化对象 - 从文件中读取类的信息,创建对象,并依次读取成员变量的值赋值给对象。

2、定义支持序列化的类

    2.1 派生自CObject类

    2.2 添加序列化的声明宏DECLARE_SERIAL(CStudent)

          和实现宏IMPLEMENT_SERIAL(CStudent, CObject, 1)

    2.3 重写CObject::Serialize()函数,在函数中,完成类的成员变量的序列化。

3、一个类的完整的序列化,要求父类,成员变量,都要支持序列化。

二、序列化小例子

复制代码
  1 #include "stdafx.h"  2 #include "Serialize2.h"  3   4 #ifdef _DEBUG  5 #define new DEBUG_NEW  6 #undef THIS_FILE  7 static char THIS_FILE[] = __FILE__;  8 #endif  9  10 ///////////////////////////////////////////////////////////////////////////// 11 // The one and only application object 12  13 CWinApp theApp; 14  15 using namespace std; 16  17 class CStudent : public CObject 18 { 19     //序列化的声明宏 20     //DECLARE_SERIAL(CStudent) 21     //_DECLARE_DYNCREATE(CStudent)  22     //_DECLARE_DYNAMIC(CStudent)  23     //声明宏的展开  24     //begin 25 public:  26     static AFX_DATA CRuntimeClass classCStudent;  27  28     virtual CRuntimeClass* GetRuntimeClass() const;  29  30     static CObject* PASCAL CreateObject(); 31  32     AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, CStudent* &pOb); 33     //end 34 public: 35     CStudent(){} 36     CStudent(CString strName, int nAge) 37     { 38         m_strName = strName; 39         m_nAge = nAge; 40     } 41     //重写序列化成员虚函数 42     virtual void Serialize( CArchive& ar ); 43  44     void Show(); 45  46 public: 47     CString m_strName; 48     int        m_nAge; 49  50 }; 51 //序列化的实现宏 52 //IMPLEMENT_SERIAL(CStudent, CObject, 1) 53  54 //实现宏的展开 55 //begin 56 //创建本类的对象返回指向该对象的指针 57 CObject* PASCAL CStudent::CreateObject()  58 { 59     return new CStudent;  60 }  61  62 //_IMPLEMENT_RUNTIMECLASS(CStudent, CObject, 1, CStudent::CreateObject)  63  64 //静态变量(运行时类信息)初始化 65 AFX_DATADEF CRuntimeClass CStudent::classCStudent =  66 {  67     "CStudent",  68     sizeof(class CStudent), 69     1,  70     CStudent::CreateObject,  71     RUNTIME_CLASS(CObject),  72     NULL  73 };  74  75 //获取本类的静态变量地址(运行时类型信息地址) 76 CRuntimeClass* CStudent::GetRuntimeClass() const  77 {  78     /*return RUNTIME_CLASS(CStudent);*/ 79     return ((CRuntimeClass*)(&CStudent::classCStudent)); 80  }  81  82 //结构体变量-->目的:pModuleState->m_classList.AddHead(pNewClass); 83 //注意:是一个全局变量,在进入main()之间,已经被构造 84 AFX_CLASSINIT _init_CStudent(RUNTIME_CLASS(CStudent));  85 /*struct AFX_CLASSINIT 86 {  87     AFX_CLASSINIT(CRuntimeClass* pNewClass) 88     {  89         AfxClassInit(pNewClass);  90         { 91             AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); 92             AfxLockGlobals(CRIT_RUNTIMECLASSLIST); 93             //将本类的运行时类信息地址保存到当前程序模块状态的一个链表中 94             pModuleState->m_classList.AddHead(pNewClass); 95             AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST); 96         } 97     }  98 };*/ 99 100 //全局函数 在类中声明为友元,目的:访问类的私有成员101 CArchive& AFXAPI operator>>(CArchive& ar, CStudent* &pOb) 102 {103     pOb = (CStudent*) ar.ReadObject(RUNTIME_CLASS(CStudent)); 104     return ar; 105 } 106 //end107 108 void CStudent::Serialize( CArchive& ar )109 {110     CObject::Serialize(ar);111     if(ar.IsStoring())112     {113         ar<<m_strName<<m_nAge;114     }115     else116     {117         ar>>m_strName>>m_nAge;118     }119 }120 121 void CStudent::Show()122 {123     printf("学生姓名:%s\n", m_strName);124     printf("学生年龄:%d\n", m_nAge);125 }126 127 //写对象(序列化)128 void ObjStore(CString strFileName, CStudent *pStu)129 {130     CFile file;131     file.Open(strFileName, CFile::modeCreate | CFile::modeWrite);132     CArchive ar(&file, CArchive::store);133     ar<<pStu;134     ar.Close();135     file.Close();136 }137 138 //读对象(反序列化)139 void ObjLoad(CString strFileName)140 {141     CFile file;142     file.Open(strFileName, CFile::modeRead);143     CArchive ar(&file, CArchive::load);144     CStudent *pStu = NULL;145     ar>>pStu;146     ar.Close();147     file.Close();148     if (pStu)149     {150         pStu->Show();151     }152 }153 154 155 void WriteFile(CString strFileName)156 {157     //创建CFile对象158     CFile file;159     //创建/打开文件160     file.Open(strFileName, CFile::modeCreate | CFile::modeWrite);161     //向文件写入内容162     CArchive archive(&file, CArchive::store);163     archive<<10<<123.6<<'A';164     archive.Close();165     file.Close();    166 }167 168 void ReadFile(CString strFileName)169 {170     //创建CFile对象171     CFile file;172     //打开文件173     file.Open(strFileName, CFile::modeRead);174     //把文件中的内容读出来175     //使用档案类176     CArchive archive(&file, CArchive::load);177     int nNum;178     double dNum;179     char cNum;180     archive>>nNum>>dNum>>cNum;181     printf("%d, %lg, %c\n", nNum, dNum, cNum);182 }183 184 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])185 {186     /*CString strFileName = "C:\\test.txt";187     WriteFile(strFileName);188     ReadFile(strFileName);*/189     CStudent stu("张飞", 20);190     CString strFileName = "C:\\serial.txt";191     ObjStore(strFileName, &stu);192     ObjLoad(strFileName);193     return 0;194 }
复制代码

四、实现原理

复制代码
 1 //写入对象的过程 2 ObjStore(strFileName, &stu); 3 { 4     ar<<pStu; 5         { 6         ar.WriteObject(pOb); 7         { 8             //获取运行时类信息 9             CRuntimeClass* pClassRef = pOb->GetRuntimeClass();10             //将运行时类信息写入到文件11             WriteClass(pClassRef);12             {13                 pClassRef->Store(*this);14                 {15                     //将类的版本号、类的大小、类名依次写入文件16                     WORD nLen = (WORD)lstrlenA(m_lpszClassName);17                     ar << (WORD)m_wSchema << nLen;18                     ar.Write(m_lpszClassName, nLen*sizeof(char));19                 }20             }21             ((CObject*)pOb)->Serialize(*this);22             {23                 //将成员变量依次写入文件24                 ar<<m_strName<<m_nAge;25             }26         }27     }28 }29 30 //读取对象的过程31 ObjLoad(strFileName);32 {33     ar>>pStu;34     {35         pOb = (CStudent*) ar.ReadObject(RUNTIME_CLASS(CStudent)); 36         {37             CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag);38             {39                 pClassRef = CRuntimeClass::Load(*this, &nSchema)40                 {41                     //依次从文件中读取版本号、类的大小、类名42                     ar >> wTemp; *pwSchemaNum = wTemp;43                     ar >> nLen;44 45                     if (nLen >= _countof(szClassName) ||46                     ar.Read(szClassName, nLen*sizeof(char)) != nLen*sizeof(char))47                     {48                         return NULL;49                     }50                     szClassName[nLen] = '\0';51 52                     //获取当前程序模块状态信息53                     AFX_MODULE_STATE* pModuleState = AfxGetModuleState();54                     //遍历当前程序模块状态信息中的m_classList链表,55                     //如果找到与szClassName一样的类名的运行时类信息,返回该运行时类信息56                     for (pClass = pModuleState->m_classList; pClass != NULL;57                     pClass = pClass->m_pNextClass)58                     {59                         if (lstrcmpA(szClassName, pClass->m_lpszClassName) == 0)60                         {61                             AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);62                             return pClass;63                         }64                     }65                 }66             }67             //动态创建CStudent类的对象68             pOb = pClassRef->CreateObject();69             {70                 pObject = (*m_pfnCreateObject)();71                 {72                     return new CStudent; 73                 }74             }75             //调用Serialize()函数,为新创建的对象赋值76             pOb->Serialize(*this);77             {78                 ar>>m_strName>>m_nAge;79             }80         }81     }82 }
复制代码


结语:要想学会MFC,还是要自己经常去断点,看源码,这样才有所理解,有所悟。

0 0
原创粉丝点击