一、对象的序列化
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,还是要自己经常去断点,看源码,这样才有所理解,有所悟。