天天看點

MFC深入淺出-CObject類

CObject類

CObject 是大多數MFC類的根類或基類。CObject類有很多有用的特性:對運作時類資訊的支援,對動态建立的支援,對串行化的支援,對象診斷輸出,等等。MFC從CObject派生出許多類,具備其中的一個或者多個特性。程式員也可以從CObject類派生出自己的類,利用CObject類的這些特性。

本章将讨論 MFC如何設計CObject類的這些特性。首先,考察CObject類的定義,分析其結構和方法(成員變量和成員函數)對CObject特性的支援。然後,讨論CObject特性及其實作機制。

CObject的結構

以下是 CObject類的定義:

class CObject

{

public:

// 與動态建立相關的函數

virtual CRuntimeClass* GetRuntimeClass() const;

析構函數

virtual ~CObject(); // virtual destructors are necessary

// 與構造函數相關的記憶體配置設定函數,可以用于DEBUG下輸出診斷資訊

void* PASCAL operator new(size_t nSize);

void* PASCAL operator new(size_t, void* p);

void PASCAL operator delete(void* p);

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)

void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);

#endif

// 預設情況下,複制構造函數和指派構造函數是不可用的

// 如果程式員通過傳值或者指派來傳遞對象,将得到一個編譯錯誤

protected:

// 預設構造函數

CObject();

private:

// 複制構造函數,私有

CObject(const CObject& objectSrc); // no implementation

// 指派構造函數,私有

void operator=(const CObject& objectSrc); // no implementation

// Attributes

// 與運作時類資訊、串行化相關的函數

BOOL IsSerializable() const;

BOOL IsKindOf(const CRuntimeClass* pClass) const;

// Overridables

virtual void Serialize(CArchive& ar);

// 診斷函數

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

// Implementation

// 與動态建立對象相關的函數

static const AFX_DATA CRuntimeClass classCObject;

#ifdef _AFXDLL

static CRuntimeClass* PASCAL _GetBaseClass();

};

由上可以看出, CObject定義了一個CRuntimeClass類型的靜态成員變量:

CRuntimeClass classCObject

還定義了幾組函數:

構造函數析構函數類,

診斷函數,

與運作時類資訊相關的函數,

與串行化相關的函數。

其中,一個靜态函數: _GetBaseClass;五個虛拟函數:析構函數、GetRuntimeClass、Serialize、AssertValid、Dump。這些虛拟函數,在CObject的派生類中應該有更具體的實作。必要的話,派生類實作它們時可能要求先調用基類的實作,例如Serialize和Dump就要求這樣。

靜态成員變量 classCObject和相關函數實作了對CObjet特性的支援。

CObject類的特性

下面,對三種特性分别描述,并說明程式員在派生類中支援這些特性的方法。

對運作時類資訊的支援

該特性用于在運作時确定一個對象是否屬于一特定類(是該類的執行個體),或者從一個特定類派生來的。 CObject提供IsKindOf函數來實作這個功能。

從 CObject派生的類要具有這樣的特性,需要:

定義該類時,在類說明中使用 DECLARE_DYNAMIC(CLASSNMAE)宏;

在類的實作檔案中使用 IMPLEMENT_DYNAMIC(CLASSNAME,BASECLASS)宏。

對動态建立的支援

前面提到了動态建立的概念,就是運作時建立指定類的執行個體。在MFC中大量使用,如前所述架構視窗對象、視對象,還有文檔對象都需要由文檔模闆類(CDocTemplate)對象來動态的建立。

從CObject派生的類要具有動态建立的功能,需要:

定義該類時,在類說明中使用DECLARE_DYNCREATE(CLASSNMAE)宏;

定義一個不帶參數的構造函數(預設構造函數);

在類的實作檔案中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏;

使用時先通過宏RUNTIME_CLASS得到類的RunTime資訊,然後使用CRuntimeClass的成員函數CreateObject建立一個該類的執行個體。

例如:

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CNname)

//CName 必須有一個預設構造函數

CObject* pObject = pRuntimeClass->CreateObject();

// 用IsKindOf檢測是否是CName類的執行個體

Assert( pObject->IsKindOf(RUNTIME_CLASS(CName));

對序列化的支援

“序列化”就是把對象内容存入一個檔案或從一個檔案中讀取對象内容的過程。從 CObject派生的類要具有序列化的功能,需要:

定義該類時,在類說明中使用DECLARE_SERIAL(CLASSNMAE)宏;

在類的實作檔案中使用IMPLEMENT_SERIAL(CLASSNAME,BASECLASS)宏;

覆寫Serialize成員函數。(如果直接調用Serialize函數進行序列化讀寫,可以省略前面三步。)

對運作時類資訊的支援、動态建立的支援、串行化的支援層(不包括直接調用Serailize實作序列化),這三種功能的層次依次升高。如果對後面的功能支援,必定對前面的功能支援。支援動态建立的話,必定支援運作時類資訊;支援序列化,必定支援前面的兩個功能,因為它們的聲明和實作都是後者包含前者。

綜合示例:

定義一個支援串行化的類CPerson:

class CPerson : public CObject

DECLARE_SERIAL( CPerson )

CPerson(){}{};

CString m_name;

WORD m_number;

void Serialize( CArchive& archive );

// rest of class declaration

} ;

實作該類的成員函數 Serialize,覆寫CObject的該函數:

void CPerson::Serialize( CArchive& archive )

// 先調用基類函數的實作

CObject::Serialize( archive );

// now do the stuff for our specific class

if( archive.IsStoring() )

archive << m_name << m_number;

else

archive >> m_name >> m_number;

}

使用運作時類資訊:

CPerson a;

ASSERT( a.IsKindOf( RUNTIME_CLASS( CPerson ) ) );

ASSERT( a.IsKindOf( RUNTIME_CLASS( CObject ) ) );

動态建立:

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson)

//Cperson 有一個預設構造函數

Assert( pObject->IsKindOf(RUNTIME_CLASS(CPerson));

繼續閱讀