我只知道DECLARE_DYNAMIC支持运行时类型识别,DECLARE_DYNCREATE支持动态创建,DECLARE_SERIAL支持串行化。可不知道从CObject类派生自己的类时,分别在什么情况下需要使用这三个宏???比如:有一个类:class CMessg : public CObject
{
protected:
DECLARE_DYNCREATE(CMessg)
public:
CMessg();
CString m_strText;
virtual void Serialize(CArchive& ar);
....
}
类的实现文件中有:
IMPLEMENT_DYNCREATE(CMessg, CObject)
void CMessg::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_strText;
}
else
{
ar >> m_strText;
}
}
这个类只是DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE,并没有DECLARE_SERIAL/IMPLEMENT_SERIAL.它怎么支持了串行化呢????更奇怪的是我把DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE也注释掉后,这个程序居然还能正确运行。我一头雾水,请各位前辈指点。谢谢!!!!
{
protected:
DECLARE_DYNCREATE(CMessg)
public:
CMessg();
CString m_strText;
virtual void Serialize(CArchive& ar);
....
}
类的实现文件中有:
IMPLEMENT_DYNCREATE(CMessg, CObject)
void CMessg::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_strText;
}
else
{
ar >> m_strText;
}
}
这个类只是DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE,并没有DECLARE_SERIAL/IMPLEMENT_SERIAL.它怎么支持了串行化呢????更奇怪的是我把DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE也注释掉后,这个程序居然还能正确运行。我一头雾水,请各位前辈指点。谢谢!!!!
解决方案 »
- 控件、菜单、各种资源 ID 重复了会怎么样
- HTTP/1.1 200 OK为什么得到的想要的页面代码而是text/javascript代码
- 打印的问题,有的机器上成功,但有的失败
- 请问怎么得到CMDIFramWnd各个窗口时的切换消息
- WSAAsyncSelect 的问题,如何取消FD_READ事件?为什么FD_READ 事件多次响应? 我在线等~~, 贵在参与,大家进来!!!
- 【请教】如何将ORACLE中读取的Date类型转换为time_t/struct tm类型.详见内.
- 打印机和磁卡问题?
- 菜鸟 提个难问题: typedef int(_cdecl *Connect)(int i);
- 关于用PV3D开发虚拟图书馆的问题?
- 今天出现了这样一个错误是怎么回事啊 ShowControlBar' : undeclared identifier
- 50分请教TCP/IP报文发送难题!谢谢先了!
- 朱门空调冻 路有热死骨 散分100
Serialize用于Persistence(永久保存)机制,只有进行文件读写的时候才会用到,才会动态创建,没有涉及到该类的动态创建话运行当然还是正常的 。你的m_strText大约也不是CMessg吧,所以你实际上没有进行CMessg的动态创建。DECLARE_SERIAL是在DECLARE_DYNCREATE的基础上加上运算符<<、>>的重载,以及一系列的工作(如文件名的选择,缓冲区的建立,数据的读写,文件开关等等),使其具有
DECLARE_DYNAMIC表明的是支持类型信息, 有了这个宏,我们就可以判断一个类究竟是什么类,比如
class A;
class B:public A;
A a;
B b;
现在有一个指针 class *pA 它指向一个对象, 请问你怎么知道pA指向的是a对象还是b对象,这是如果有类型信息,我们就可以知道pA到底是什么对象, 其实,它内部的实现原理是一个字符串,所以,进行这个判断时,实际上是字符串比较.
它实际上是用类CRunTime class记录了类的静态创建函数的地址.这个特性在很多地方需要使用.就在下面说的DECLARE_SERIAL就是一个经典的例子.
动态创建主要用在 "我不知道要创建的对象就是是什么类,但是我知道它肯定是从某个基类派生的".
可以肯定,存储机制中必须要有能够判断类种类的代码.所以,序列化机制DECLARE_SERIAL包含了DECLARE_DYNAMIC,这样在存储进入文件的时候,可以将类名称存储到文件中.
OK,现在我们载入的时候可以知道我们要载入什么类了,但是,我们又要怎么去创建它呢? 所以DECLARE_SERIAL也包含了DECLARE_DYNCREATE,它用于创建对象.
那么,DECLARE_SERIAL到底有什么特殊的地方呢?首先,它必须实现operator>>(具体原因可以看看深入浅出,还有版本控制,这样,我们在处理序列化时,可以很灵活.
#define DECLARE_SERIAL(class_name) \
_DECLARE_DYNCREATE(class_name) \
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);一看就明白,然來DECLARE_DYNCREATE宏,只是加了一個重裝">>"操作符的成員函數.依此類推,就是這麼簡簞.
首先记住一点,DECLARE_SERIAL最主要的用途是一种智能存储.所以我们可以不用这个智能特性.
当我们没有DECLARE_SERIAL,而有void CMessg::Serialize(CArchive& ar)时,我们只能这样进行存储
CDocument::Serialize(ar)
{
if (ar.isstoring())
{
//存储一个对象
pMessg->Serialize(ar);
}
else
{
//必须非常明确的指出New一个 CMessg对象;
pMessg = new CMessg;
pMessg->Serialize(ar);
}
}
在上面这个例子中,根本没有利用MFC为我们设计的序列化只能机制.再看下面一个例子CDocument::Serialize(ar)
{
if (ar.isstoring())
{
//存储一个对象
ar << pMessg;
}
else
{
//必须非常明确的指出New一个 CMessg对象;
ASSERT(pMessg == NULL);
ar >> pMessg;
}
}很神奇吧, ar是怎么根据文件(强调一下,是根据文件,而不是硬编码)判断需要创建什么类的.
它大概有这么几个步骤:
1. 因为DECLARE_SERIAL重载了>>操作符,所以可以保证是调用CMessg类的>>函数.
2. >>函数实际上调用的是ar的ReadObject(CRuntimeClass*)函数
3. ReadObject首先从文件中读取类判断信息(可能是一个字符串,可能是一个类索引),得到Class对应的ClassName;
4. 程序的模块状态中有所有的RuntimeClass的列表,因此,查找对应的程序支持的RuntimeClass(对比ClassName),获得对应的RuntimeClass;
5. RuntimeClass中含有创建对象的方法CreateObject,调用它,创建对应的对象.这里,因为CreateObject实际就是 New 一个对象,类似 new CMessg; 所以,为了支持序列化,必须有没有参数的构造函数.
6. 创建对象之后,调用Seralize(ar),读入真正的对象的信息.
7. 将对象的指针返回.
8. pMessg就指向一个对应的对象了.