|
[VC++学习]《精通MFC》——第四章(IV) 读书笔记
|
为类定义一个不带参数的构造函数(默认构造函数)。这是因为动态创建过程要使用该构造函数进行初始化。
在类实现文件中使用IMPLEMENT_DYNCREATE宏。该宏除了完成IMPLEMENT_DYNAMIC的功能外,还负责实现DECLARE_DYNCREATE中声明的静态成员CreateObject:
CObject* PASCAL class_name::CreateObject()
{return new class_name;}
IMPLEMENT_DYNCREATE宏还将CRuntimeClass的m_pfnCreateObject成员设置为类的CreateObject。但仍将wSchema设置为0xFFFF,这意味着不支持序列化,将class_init设置为NULL,表示当前类CRuntimeClass不会被加入到全局的CRuntimeClass链中。
下面就可以用CRuntimeClass的CreateObjec函数,并将下列代码动态创建对象。失败时,CreateObject返回NULL,而不是引发异常:
//动态创建
CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson);
CObject* pObject = pRuntimeClass->CreateObject();
ASSERT(pObject->IsKindOf(RUNTIME_CLASS(CPerson)));
CPerson* pPerson2 = static_cast<CPerson*>(pObject);
//
pPerson2->m_firstName = "Xiaohua";
pPerson2->m_lastName = "Liu";
delete pPerson2;
2.1 序列化
序列化是比动态创建更高级的功能,它提供了将对象保存到文件或其它存储设备以及从存储中重建对象的能力。
添加序列化支持
CObject提供了如下两个成员支持序列化:IsSerializable和Serialize。第一个用来判断是否支持序列化,而第二个则进行实际的序列化。
当类的CRuntimeClass成员的m_wSchema为0xFFFF时,表示该对象不支持序列化:
BOOL CObject::IsSerializable()const
{
Return (GetRuntimeClass()->m_wSchema != 0xFFFF);
}
因此为了支持序列化,必须把类的CRuntimeClass静态成员的m_wSchema成员设置为非0xFFFF值。
这项设置工作是通过一组宏来实现的。首先在类声明中使用DECLARE_SERIAL宏。该宏除了完成DECLARE_DYNCREATE所做的工作外,还声明了友元函数operator>>,以支持从ar中创建对象:
#define DECLARE_SERIAL(class_name)
_DECLARE_DYNCREATE(class_name)
AFX_API friend Carchive& AFXAPI operator>>(Carchive& ar,class_name*&pOb);
然后在实现文件中使用IMPLEMENT_SERIAL宏。该宏的第三个参数是架构编号。架构编号实质上是类对象的版本号,架构编号使用大于或等于零的整数。
如果要使Serialize成员函数能够读取多个版本(即,读取应用程序的不同版本写入的文件),可将VERSIONABLE_SCHEMA值作为IMPLEMENT_SERIAL宏的参数。
该宏除了有DECLARE_DYNCREATE的全部功能外,还要:
设置CRuntimeClass静态成员的m_pClassInit成员。
将类的CRuntimeClass静态成员添加到全局运行时类信息链表中,也就是设置CRuntimeClass静态成员的m_pClassInit成员。
下面是DYNCREATE的展开形式(省去了与IMPLEMENT_DYNAMIC相同的部分):
AFX_COMDAT AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name));
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema, class_name::CreateObject,&_init_##class_name)
实现operator>>函数
CArchive& AFXAPI operator>>(CArchive& ar,class_name* &pOb)
{
pOb = (class_name)ar.ReadObject(RUNTIME_CLASS(class_nmae)) return ar;
}
有了上述准备工作,派生类只要重写Serialize成员函数即可。
virtual void Serialize(CArchive& ar);
CArchive对象具有成员函数IsStoring,该成员函数指示Serialize正在存储(写入数据)还是正在加载(读取数据)。用IsStoring的结果作为参考,使用输出运算符(<<)将对象数据插入到CArchive对象中,或使用输入运算符(>>)提取数据。
CArchive类
CArchive对象提供了一个类型安全缓冲机制,用于将可序列化对象写入CFile对象或从中读取可序列化对象。通常,CFile对象表示磁盘文件,也可以表示“剪切板”的内存文件(CsharedFile对象)。
CArchive对象要么存储数据,要么加载数据,但不能同时进行。CArchive对象的寿命只限于将对象写入文件或从文件读取对象的一次传递 。因此,需要两个连续创建的CArchive对象将数据序列化到文件,然后从文件反序列化数据。
创建CArchive对象
显式创建创建CArchive对象,首先需要创建构造CFile对象,然后将CFile对象传递到CArchive的构造函数。如下所示:
CFile theFile;
theFile.open(…, CFile::modeWrite);
CArchive archive(&theFile, CArchive::store);
CArchive构造函数的第二个参数指定是向文件中存储数据还是从文件中加载数据。对象的Serialize函数通过调用CArchive对象的IsStoring函数来检查该状态。
构造文件对象
通过两个不骤构造CFile对象。
创建文件对象,但不指定路径或权限标志。通常通过在堆栈上声明CFile变量来创建文件对象。
调用文件对象的Open成员函数,并提供路径和权限标志。
Open成员函数的原型如下:
Virtual bool Open(LPCTSTR lpszFileName, UINT nOpenFlags, CfileException* pError = NULL); |
|
00oo.. 发表于 2005/11/13 10:12:39
|
|