按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
{
WORD w;
ar 》》 w;
m_nPenWidth = w;
m_pointArray。Serialize(ar);
}
}
528
…………………………………………………………Page 591……………………………………………………………
第8章 Document…View 深入探討
CObject 类别
为什么绝大部份的MFC 类别,以及许多你自己的类别,都要从CObject 衍生下来呢?
因为当一个类别衍生自CObject,它也就继承了许多重要的性质。CObject 这个「老祖
宗」至少提供两个机能(两个虚拟函数):IsKindOf 和IsSerializable 。
IsKindOf
当Framework 掌握「类别型录网」这张王牌,要设计出IsKindOf 根本不是问题。所谓
IsKindOf 就是RTTI 的化身,用白话说就是「xxx 对象是一种xxx 类别吗?」例如「长
臂猿是一种哺乳类吗?」「蓝鲸是一种鱼类吗?」凡支持RTTI 的程序就必须接受这类
询问,并对前者回答Yes ,对后者回答No 。
下面是CObject::IsKindOf 虚拟函数的源代码:
// in OBJCORE。CPP
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
// simple SI case
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis…》IsDerivedFrom(pClass);
}
BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
{
// simple SI case
const CRuntimeClass* pClassThis = this;
while (pClassThis != NULL)
{
if (pClassThis == pBaseClass)
return TRUE;
pClassThis = pClassThis…》m_pBaseClass;
}
return FALSE; // walked to the top; no match
}
这项作为,也就是在图8…9 中借着m_pBaseClass 寻根。只要在寻根过程中比对成功,
就传回TRUE , 否则传回FALSE 。而你知道, 图8…9 的「类别型录网」是靠
DECLARE_DYNAMIC 和IMPLEMENT_DYNAMIC 宏构造起来的。第3 章的
529
…………………………………………………………Page 592……………………………………………………………
第篇 深入 MFC 程式設計
「RTTI 」一节对此多有说明。
IsSerializable
一个类别若要能够进行Serialization 动作,必须准备Serialize 函数,并且在「类别型录
网」中自己的那个CRuntimeClass 元素里的schema 字段里设立0xFFFF 以外的号码,
代表资料格式的版本(这样才能提供机会让设计较佳的Serialize 函数能够区分旧版资料
或新版资料, 避免牛头不对马嘴的困惑) 。这些都是DECLARE_SERIAL 和
IMPLEMENT_SERIAL 宏的责任范围。
CObject::classCObject CCmdTarget::classCCmdTarget CWinThread::classCWinThread
“CObject” “CCmdTarget” “CWinThread”
m_pfnCreateObject NULL m_pfnCreateObject NULL m_pfnCreateObject NULL
m_pBaseClass m_pBaseClass m_pBaseClass
m_pNextClass m_pNextClass m_pNextClass
NULL
NULL
CFrameWnd::classCFrameWnd CWnd::classCWnd CWinApp::classCWinApp
“CFrameWnd” “CWnd” “CWinApp”
m_pfnCreateObject m_pfnCreateObject m_pfnCreateObject NULL
m_pBaseClass m_pBaseClass m_pBaseClass
m_pNextClass m_pNextClass m_pNextClass
CDocument::classCDocument CView::classCView
“CDocument” “CView”
m_pfnCreateObject m_pfnCreateObject
NULL NULL
m_pBaseClass m_pBaseClass
m_pNextClass m_pNextClass
CRuntimeClass::pFirstClass
图8…9 DECLARE_ 和IMPLEMENT_ 宏合力构造起这张网。于是RTTI
和Dynamic Creation 和Serialization 等机能便可轻易达成。
530
…………………………………………………………Page 593……………………………………………………………
第8章 Document…View 深入探討
CObject 提供了一个虚拟函数,让程序在执行时期判断某类别的schema 号码是否为
0xFFFF,藉此得知它是否可以Serialize:
BOOL CObject::IsSerializable() const
{
return (GetRuntimeClass()…》m_wSchema != 0xffff);
}
CObject::Serialize
这是一个虚拟函数。每一个希望具备Serialization 能力的类别都应该改写它。事实上
Wizard 为我们做出来的程序代码中也都会自动加上这个函数的调用动作。MFC 手册上总
是说,每一个你所改写的Serialize 函数都应该在第一时间调用此一函数,那么是不是
CObject::Serialize 之中有什么重要的动作?
// in AFX。INL
_AFX_INLINE void CObject::Serialize(CArchive&)
{ /* CObject does not serialize anything by default */ }
不,什么也没有。所以,现阶段(至少截至MFC 4。0 )你可以不必理会手册上的谆谆告
诲。然而,Microsoft 很有可能改变CObject::Serialize 的内容,届时没有遵循告诲的人
恐怕就后悔了。
CArchive 类别
谈到Serialize 就不能不谈CArchive,因为serialize 的对象(无论读或写)是一个
CArchive 对象,这一点相信你已经从上面数节讨论中熟悉了。基本上你可以想象archive
相当于文件,不过它其实是文件之前的一个内存缓冲区。所以我们才会在前面的「台
面下的Serialize 奥秘」中看到这样的动作:
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
{
CFile* pFile = NULL;
pFile = GetFile(lpszPathName; CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive; &fe);
// 令file 和archive 产生关联
531
…………………………………………………………Page 594……………………………………………………………
第篇 深入 MFC 程式設計
CArchive saveArchive(pFile; CArchive::store |
CArchive::bNoFlushOnDelete);
。。。
Serialize(saveArchive); //对着 archive 做serialize 动作
。。。
saveArchive。Close();
ReleaseFile(pFile; FALSE);
}
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
CFile* pFile = GetFile(lpszPathName;
CFile::modeRead|CFile::shareDenyWrite; &fe);
// 令file 和archive 产生关联
CArchive loadArchive(pFile; CArchive::load |
CArchive::bNoFlushOnDelete);
。。。
Serialize(loadArchive); // 对着archive 做serialize 动作
。。。
loadArchive。Close();