一、对象的序列化

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 //end
107 
108 void CStudent::Serialize( CArchive& ar )
109 {
110     CObject::Serialize(ar);
111     if(ar.IsStoring())
112     {
113         ar<<m_strName<<m_nAge;
114     }
115     else
116     {
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,还是要自己经常去断点,看源码,这样才有所理解,有所悟。

版权声明:本文为inrgihc原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/inrgihc/articles/8057160.html