17.2.3 基于CObject的类的功能
对于从MFC类CObject派生的类来说,它们有3个层次的功能。在一个类中获得的功能层次取决于在类定义中使用的3种不同的宏,见表17-2。
表 17-2
|
宏
|
功 能
|
|
DECLARE_DYNAMIC()
|
支持运行时类信息
|
|
DECLARE_DYNCREATE()
|
支持运行时类信息和动态对象创建
|
|
DECLARE_SERIAL()
|
支持运行时类信息、动态对象创
建和对象的序列化
|
其中每个宏都需要一个前缀为IMPLEMENT_而非DECLARE_的互补宏,这些互补宏存放在包含类实现的文件中。由表17-2可知,这些宏提供的功能逐渐增多,由于第三个宏DECLARE_SERIAL()不仅包含前两个宏的功能,而且提供了另外的功能,所以本书将主要讨论它。这就是您在自己的类中支持序列化时应当使用的宏。它要求在包含类实现的文件中添加宏IMPLEMENT_SERIAL()。
您也许想知道,为什么文档类CSketcherDoc要使用DECLARE_DYNCREATE()宏,而不使用DECLARE_SERIAL()宏。DECLARE_DYNCREATE()宏在它出现的类中动态地创建该类的对象。DECLARE_SERIAL()宏能够对类进行序列化,并且能够动态地创建类对象,所以它包含了DECLARE_DYNCREATE()宏的功能。文档类CSketcherDoc不需要序列化,因为框架只需要组合这个类对象,然后还原它的数据成员的值;但是,一个文档的数据成员必须是可序列化的,因为这是用于存储和检索它们的过程。
将序列化添加到类中的宏
如果在基于CObject的类的定义中有DECLARE_SERIAL()宏,那么可以访问CObject提供的序列化支持。这包括特殊的new和delete操作符,它们把内存泄漏检测加入到调试模式中。在使用这个宏时不需要做任何事情,因为它将自动完成操作。DECLARE_SERIAL()宏要求把类名指定为参数,所以对CElement类进行序列化时,需要在类定义中添加下列行:
- DECLARE_SERIAL(CElement)
此处不需要使用分号,因为这是一个宏,而不是C++(www.cppentry.com)语句。
这个宏在类定义中的位置无关紧要,但是如果能够始终把它放在第一行,那么即使类定义包括许多行代码,也能够知道它是否存在。
IMPLEMENT_SERIAL()宏存储在类的实现文件中,它要求指定3个参数。第一个参数是类的名称,第二个参数是直接基类的名称,第三个参数是一个标识模式号的无符号32位整数,对于Sketcher程序来说就是版本号。如果写入对象和读取对象时使用的程序版本不同,这时类也可能不同,那么可能出现一些问题,而这个模式号能够防止序列化过程出现的这些问题。
例如,可以添加下列行到CElement类的实现中:
- IMPLEMENT_SERIAL(CElement, CObject, 1001)
如果以后修改了类定义,那么需要把这个模式号修改成另外一个不同的模式号,如1002。如果这个程序试图从当前活动程序中读取利用不同模式号编写的数据,那么将抛出一个异常。这个宏最好是放在.cpp文件中#include指令和初始注释之后的第一行。
当CObject是类的间接基类时,例如,在CLine类的情况中,那么要使序列化能够在顶级类中操作,层次结构中的每个类都必须添加序列化宏。要使序列化能够在CLine类中操作,也必须在CElement中添加这些宏。