?? mfc教程3_ cobject類.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0041)http://www.vczx.com/tutorial/mfc/mfc3.php -->
<HTML><HEAD><TITLE>MFC教程_ CObject類</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2900.3157" name=GENERATOR></HEAD>
<BODY bgColor=#ffffff>
<OL start=3>
<P align=justify>
<LI><A name=_Toc445782393></A><A name=_Toc452640889></A><A
name=_Toc457298954></A><B>CObject類</B>
<P></P>
<P
align=justify>CObject是大多數MFC類的根類或基類。CObject類有很多有用的特性:對運行時類信息的支持,對動態創建的支持,對串行化的支持,對象診斷輸出,等等。MFC從CObject派生出許多類,具備其中的一個或者多個特性。程序員也可以從CObject類派生出自己的類,利用CObject類的這些特性。</P>
<P
align=justify>本章將討論MFC如何設計CObject類的這些特性。首先,考察CObject類的定義,分析其結構和方法(成員變量和成員函數)對CObject特性的支持。然后,討論CObject特性及其實現機制。</P>
<OL>
<P align=justify>
<LI><A name=_Toc445888991></A><A name=_Toc445782394></A><A
name=_Toc452640890></A><A name=_Toc457298955></A><B>CObject的結構</B>
<P></P>
<P align=justify>以下是CObject類的定義:</P>
<P align=justify>class CObject</P>
<P align=justify>{</P>
<P align=justify>public:</P>
<P align=justify></P>
<P align=justify>//與動態創建相關的函數</P>
<P align=justify>virtual CRuntimeClass* GetRuntimeClass() const;</P>
<P align=justify>析構函數</P>
<P align=justify>virtual ~CObject(); // virtual destructors are
necessary</P>
<P align=justify></P>
<P align=justify>//與構造函數相關的內存分配函數,可以用于DEBUG下輸出診斷信息</P>
<P align=justify>void* PASCAL operator new(size_t nSize);</P>
<P align=justify>void* PASCAL operator new(size_t, void* p);</P>
<P align=justify>void PASCAL operator delete(void* p);</P>
<P align=justify>#if defined(_DEBUG) &&
!defined(_AFX_NO_DEBUG_CRT)</P>
<P align=justify>void* PASCAL operator new(size_t nSize, LPCSTR
lpszFileName, int nLine);</P>
<P align=justify>#endif</P>
<P align=justify></P>
<P align=justify>//缺省情況下,復制構造函數和賦值構造函數是不可用的</P>
<P align=justify>//如果程序員通過傳值或者賦值來傳遞對象,將得到一個編譯錯誤</P>
<P align=justify>protected:</P>
<P align=justify>//缺省構造函數</P>
<P align=justify>CObject();</P>
<P align=justify>private:</P>
<P align=justify>//復制構造函數,私有</P>
<P align=justify>CObject(const CObject& objectSrc); // no
implementation</P>
<P align=justify>//賦值構造函數,私有</P>
<P align=justify>void operator=(const CObject& objectSrc); // no
implementation</P>
<P align=justify></P>
<P align=justify>// Attributes</P>
<P align=justify>public:</P>
<P align=justify>//與運行時類信息、串行化相關的函數</P>
<P align=justify>BOOL IsSerializable() const;</P>
<P align=justify>BOOL IsKindOf(const CRuntimeClass* pClass) const;</P>
<P align=justify>// Overridables</P>
<P align=justify>virtual void Serialize(CArchive& ar);</P>
<P align=justify>// 診斷函數</P>
<P align=justify>virtual void AssertValid() const;</P>
<P align=justify>virtual void Dump(CDumpContext& dc) const;</P>
<P align=justify></P>
<P align=justify>// Implementation</P>
<P align=justify>public:</P>
<P align=justify>//與動態創建對象相關的函數</P>
<P align=justify>static const AFX_DATA CRuntimeClass classCObject;</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>static CRuntimeClass* PASCAL _GetBaseClass();</P>
<P align=justify>#endif</P>
<P align=justify>};</P>
<P align=justify></P>
<P align=justify>由上可以看出,CObject定義了一個CRuntimeClass類型的靜態成員變量:</P>
<P align=justify>CRuntimeClass classCObject</P>
<P align=justify>還定義了幾組函數:</P>
<P align=justify>構造函數析構函數類,</P>
<P align=justify>診斷函數,</P>
<P align=justify>與運行時類信息相關的函數,</P>
<P align=justify>與串行化相關的函數。</P>
<P
align=justify>其中,一個靜態函數:_GetBaseClass;五個虛擬函數:析構函數、GetRuntimeClass、Serialize、AssertValid、Dump。這些虛擬函數,在CObject的派生類中應該有更具體的實現。必要的話,派生類實現它們時可能要求先調用基類的實現,例如Serialize和Dump就要求這樣。</P>
<P align=justify>靜態成員變量classCObject和相關函數實現了對CObjet特性的支持。</P>
<P align=justify></P>
<LI><A name=_Toc445888992></A><A name=_Toc445782395></A><A
name=_Toc452640891></A><A name=_Toc457298956></A><B>CObject類的特性</B>
<P></P></LI></OL></LI></OL>
<P align=justify>下面,對三種特性分別描述,并說明程序員在派生類中支持這些特性的方法。</P>
<OL>
<P align=justify>
<LI>對運行時類信息的支持
<P></P></LI></OL>
<P
align=justify>該特性用于在運行時確定一個對象是否屬于一特定類(是該類的實例),或者從一個特定類派生來的。CObject提供IsKindOf函數來實現這個功能。</P>
<P align=justify>從CObject派生的類要具有這樣的特性,需要:</P>
<UL>
<P align=justify>
<LI>定義該類時,在類說明中使用DECLARE_DYNAMIC(CLASSNMAE)宏;
<P></P>
<P align=justify></P>
<LI>在類的實現文件中使用IMPLEMENT_DYNAMIC(CLASSNAME,BASECLASS)宏。
<P></P></LI></UL>
<P align=justify></P>
<OL>
<P align=justify>
<LI>對動態創建的支持
<P></P></LI></OL>
<P
align=justify>前面提到了動態創建的概念,就是運行時創建指定類的實例。在MFC中大量使用,如前所述框架窗口對象、視對象,還有文檔對象都需要由文檔模板類(CDocTemplate)對象來動態的創建。</P>
<P align=justify>從CObject派生的類要具有動態創建的功能,需要:</P>
<UL>
<P align=justify>
<LI>定義該類時,在類說明中使用DECLARE_DYNCREATE(CLASSNMAE)宏;
<P></P>
<P align=justify></P>
<LI>定義一個不帶參數的構造函數(默認構造函數);
<P></P>
<P align=justify></P>
<LI>在類的實現文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏;
<P></P>
<P align=justify></P>
<LI>使用時先通過宏RUNTIME_CLASS得到類的RunTime信息,然后使用CRuntimeClass的成員函數CreateObject創建一個該類的實例。
<P></P></LI></UL>
<P align=justify>例如:</P>
<P align=justify>CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CNname)</P>
<P align=justify>//CName必須有一個缺省構造函數</P>
<P align=justify>CObject* pObject = pRuntimeClass->CreateObject();</P>
<P align=justify>//用IsKindOf檢測是否是CName類的實例</P>
<P align=justify>Assert( pObject->IsKindOf(RUNTIME_CLASS(CName));</P>
<P align=justify></P>
<OL>
<P align=justify>
<LI>對序列化的支持
<P></P></LI></OL>
<DIR>
<P
align=justify>“序列化”就是把對象內容存入一個文件或從一個文件中讀取對象內容的過程。從CObject派生的類要具有序列化的功能,需要:</P></DIR>
<UL>
<P align=justify>
<LI>定義該類時,在類說明中使用DECLARE_SERIAL(CLASSNMAE)宏;
<P></P>
<P align=justify></P>
<LI>定義一個不帶參數的構造函數(默認構造函數);
<P></P>
<P align=justify></P>
<LI>在類的實現文件中使用IMPLEMENT_SERIAL(CLASSNAME,BASECLASS)宏;
<P></P>
<P align=justify></P>
<LI>覆蓋Serialize成員函數。(如果直接調用Serialize函數進行序列化讀寫,可以省略前面三步。)
<P></P></LI></UL>
<P align=justify></P>
<P
align=justify>對運行時類信息的支持、動態創建的支持、串行化的支持層(不包括直接調用Serailize實現序列化),這三種功能的層次依次升高。如果對后面的功能支持,必定對前面的功能支持。支持動態創建的話,必定支持運行時類信息;支持序列化,必定支持前面的兩個功能,因為它們的聲明和實現都是后者包含前者。</P>
<OL>
<P align=justify>
<LI>綜合示例:
<P></P></LI></OL>
<P align=justify>定義一個支持串行化的類CPerson:</P>
<P align=justify>class CPerson : public CObject</P>
<P align=justify>{</P>
<DIR>
<P align=justify>public:</P></DIR>
<P align=justify>DECLARE_SERIAL( CPerson )</P>
<P align=justify>// 缺省構造函數</P>
<P align=justify>CPerson(){}{};</P>
<P align=justify></P>
<P align=justify>CString m_name;</P>
<P align=justify>WORD m_number;</P>
<P align=justify></P>
<P align=justify>void Serialize( CArchive& archive );</P>
<P align=justify></P>
<P align=justify>// rest of class declaration</P>
<P align=justify>};</P>
<P align=justify></P>
<P align=justify>實現該類的成員函數Serialize,覆蓋CObject的該函數:</P>
<P align=justify>void CPerson::Serialize( CArchive& archive )</P>
<P align=justify>{</P>
<P align=justify>// 先調用基類函數的實現</P>
<P align=justify>CObject::Serialize( archive );</P>
<P align=justify></P>
<P align=justify>// now do the stuff for our specific class</P>
<P align=justify>if( archive.IsStoring() )</P>
<P align=justify>archive << m_name << m_number;</P>
<P align=justify>else</P>
<P align=justify>archive >> m_name >> m_number;</P>
<P align=justify>}</P>
<P align=justify></P>
<P align=justify>使用運行時類信息:</P>
<P align=justify>CPerson a; </P>
<P align=justify>ASSERT( a.IsKindOf( RUNTIME_CLASS( CPerson ) ) );</P>
<P align=justify>ASSERT( a.IsKindOf( RUNTIME_CLASS( CObject ) ) );</P>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -