本文转载自:
百度百科:DECLARE_DYNCREATE
百度百科:IMPLEMENT_DYNCREATE
百度百科:DECLARE_SERIAL
百度百科:IMPLEMENT_SERIAL
DECLARE_DYNAMIC和IMPLEMENT_DYNAMIC
DECLARE_DYNCREATE和DECLARE_DYNAMIC的区别
DECLARE_DYNCREATE
DECLARE_SERIAL
MFC 六大关键技术之仿真
DECLARE_SERIAL / IMPLEMENT_SERIAL 宏
|
要将<< 和>> 两个运算子多载化,还要让Serialize 函数神不知鬼不觉地放入类别声明
之中,最好的作法仍然是使用宏。
类别之能够进行文件读写动作,前提是拥有动态生成的能力,所以,MFC 设计了两个宏
DECLARE_SERIAL 和IMPLEMENT_SERIAL:
#define DECLARE_SERIAL(class_name) \
DECLARE_DYNCREATE(class_name) \
friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
class_name::CreateObject) \
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
return ar; } \
为了在每一个对象被处理(读或写)之前,能够处理琐屑的工作,诸如判断是否第一次
出现、记录版本号码、记录文件名等工作,CRuntimeClass 需要两个函数Load 和Store
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;
CObject* CreateObject();
void Store(CArchive& ar) const;
static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
// CRuntimeClass objects linked together in simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
你已经在上一节看过Load 函数,当时为了简化,我把它的参数拿掉,改为由屏幕上获
得类别名称,事实上它应该是从文件中读一个类别名称。至于Store 函数,是把类别名
称写入文件中:
// Runtime class serialization code
CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)
{
WORD nLen;
char szClassName[64];
CRuntimeClass* pClass;
ar >> (WORD&)(*pwSchemaNum) >> nLen;
if (nLen >= sizeof(szClassName) || ar.Read(szClassName, nLen) != nLen)
return NULL;
szClassName[nLen] = ~\0~;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (lstrcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
return NULL; // not found
}
void CRuntimeClass::Store(CArchive& ar) const
// stores a runtime class description
{
WORD nLen = (WORD)lstrlenA(m_lpszClassName);
ar << (WORD)m_wSchema << nLen;
ar.Write(m_lpszClassName, nLen*sizeof(char));
}
class CScribDoc : public CDocument
{
DECLARE_DYNCREATE(CScribDoc)
...
};
class CStroke : public CObject
{
DECLARE_SERIAL(CStroke)
public:
void Serialize(CArchive&);
...
};
class CRectangle : public CObject
{
DECLARE_SERIAL(CRectangle)
public:
void Serialize(CArchive&);
...
};
class CCircle : public CObject
{
DECLARE_SERIAL(CCircle)
public:
void Serialize(CArchive&);
...
};
以及在.CPP 档中做这样的动作:
IMPLEMENT_DYNCREATE(CScribDoc, CDocument)
IMPLEMENT_SERIAL(CStroke, CObject, 2)
IMPLEMENT_SERIAL(CRectangle, CObject, 1)
IMPLEMENT_SERIAL(CCircle, CObject, 1)
然后呢?分头设计CStroke、CRectangle 和CCircle 的Serialize 函数吧。
当然,毫不令人意外地,MFC 源代码中的CObList 和CDWordArray 有这样的内容:
// in header files
class CDWordArray : public CObject
{
DECLARE_SERIAL(CDWordArray)
public:
void Serialize(CArchive&);
...
};
class CObList : public CObject
{
DECLARE_SERIAL(CObList)
public:
void Serialize(CArchive&);
...
};
// in implementation files
IMPLEMENT_SERIAL(CObList, CObject, 0)
IMPLEMENT_SERIAL(CDWordArray, CObject, 0)
而CObject 也多了一个虚拟函数Serialize:
class CObject
{
public:
virtual void Serialize(CArchive& ar);
...
}
|
IMPLEMENT_SERIAL
class_name 类的实际名字(不用引号括起来)。
base_class_name 基类的名字(不用引号括起来)。
wSchema 一个UINT类型的版本号,将被用在存档中,使得解串行程序能够识别并处理早期版本的程序所生成的数据。它的值不能是-1。
|
DECLARE_DYNAMIC和IMPLEMENT_DYNAMIC宏
IMPLEMENT_DYNAMIC是实现“运行时类型识别”宏,与之相对应的是DECLARE_DYNAMIC(声明“运行时类型识别”宏)。也就是说你在.CPP文件中如果看见有IMPLEMENT_DYNAMIC,则在.H文件中必定有DECLARE_DYNAMIC的声明。
DECLARE_DYNAMIC/DEClARE_DYNAMIC是为了确定运行时对象属于哪一个类而定义的宏。
DEClARE_DYNCREATE/IMPLEMENT_DYNCREATE是为了“动态创建"类的实例而定义的宏。new可以用来创建对象,但不是动态的。比如说,你要在程序中实现根据拥护输入的类名来创建类的实例,下面的做法是通不过的:
char szClassName[60];
cin >> szClassName;
CObject* pOb=new szClassName; //通不过
这里就要用到DEClARE_DYNCREATE/IMPLEMENT_DYNCREATE定义的功能了。
DECLARE_DYNCREATE与DECLARE_DYNAMIC区别
DECLARE_DYNAMIC 表示可以运行时识别该类
DECLARE_DYNCREATE 包含了DECLARE_DYNAMIC的功能,并且可以在运行过程中动态创建对象。如果需要动态创建类对象,需要使用这个宏定义。
DECLARE_DYNCREAT定义如下:
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name)\
static CObject* PASCALCreateObject();(这一句就是DECLARE_DYNCREATE多出来的一句)
这里是DECLARE_DYNAMIC声明的(本质上就是声明了一个CruntimClass,并且提供了一个可以获取CruntimeClass的函数)
DECLARE_DYNAMIC(class_name)
public:
staticconst CRuntimeClassclass##class_name;
virtual CRuntimeClass* GetRuntimeClass()const;
RUNTIME_CLASS的本质,就是获取该类的类型为CruntTimeClass的成员变量
((CRuntimeClass*)(&class_name::class##class_name))