動態類型識別和動態創建

運行時類信息 (CRuntimeClass 類)

動態類型識別(Runtime Type Infomation, RTTI):在程序運行的過程中辨別對象是否屬於特定類的技術。

動態創建:如果爲每個類都寫一個創建該類的全局函數的話,就能夠依靠從文件或用戶的輸入中取得此函數的內存地址,從而創建用戶動態指定的類。

一個類支持運行期識別能力需要兩個條件:

1.含有一個CRuntimeClass類型的靜態變量

2.一個可以取得CRuntimeClass對象地址的虛函數GetRuntimeClass。

CRuntimeClass類的結構(在頭文件afx.h中):

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
#ifdef _AFXDLL
	CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
#else
	CRuntimeClass* m_pBaseClass;
#endif

// Operations
	CObject* CreateObject();
	BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

	// dynamic name lookup and creation
	static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
	static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
	static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
	static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);

// Implementation
	void Store(CArchive& ar) const;
	static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);

	// CRuntimeClass objects linked together in simple list
	CRuntimeClass* m_pNextClass;       // linked list of registered classes
	const AFX_CLASSINIT* m_pClassInit;
};

要想使所有的類都具有運行期識別和動態創建的特性,必須有一個類作爲繼承體系的頂層,將它命名爲CObject,它是所有類的基類。

CObject類結構:

// class CObject is the root of all compliant objects

class AFX_NOVTABLE CObject
{
public:

// Object model (types, destruction, allocation)
	virtual CRuntimeClass* GetRuntimeClass() const;
	virtual ~CObject() = 0;  // virtual destructors are necessary

	// Diagnostic allocations
	void* PASCAL operator new(size_t nSize);
	void* PASCAL operator new(size_t, void* p);
	void PASCAL operator delete(void* p);
	void PASCAL operator delete(void* p, void* pPlace);

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
	// for file name/line number tracking using DEBUG_NEW
	void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
	void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine);
#endif

	// Disable the copy constructor and assignment by default so you will get
	//   compiler errors instead of unexpected behaviour if you pass objects
	//   by value or assign objects.
protected:
	CObject();
private:
	CObject(const CObject& objectSrc);              // no implementation
	void operator=(const CObject& objectSrc);       // no implementation

// Attributes
public:
	BOOL IsSerializable() const;
	BOOL IsKindOf(const CRuntimeClass* pClass) const;

// Overridables
	virtual void Serialize(CArchive& ar);

#if defined(_DEBUG) || defined(_AFXDLL)
	// Diagnostic Support
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

// Implementation
public:
	static const CRuntimeClass classCObject;	//運行時類信息
#ifdef _AFXDLL
	static CRuntimeClass* PASCAL _GetBaseClass();
	static CRuntimeClass* PASCAL GetThisClass();
#endif
};

幾個幫助簡化代碼的宏:

1. RUNTIME_CLASS :爲了方便訪問類的CRuntimeClass結構而定義的宏。

#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

2. DECLARE_DYNAMIC:聲明支持動態類信息

#define DECLARE_DYNAMIC(class_name) \
public: \
	static const CRuntimeClass class##class_name; \
	virtual CRuntimeClass* GetRuntimeClass() const; \

3. IMPLEMENT_RUNTIMECLASS: 實例化CRuntimeClass對象,爲了方便定義IMPLEMENT_DYNAMIC 宏

#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
	AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
		#class_name, sizeof(class class_name), wSchema, pfnNew, \
			RUNTIME_CLASS(base_class_name), NULL, class_init }; \
	CRuntimeClass* class_name::GetRuntimeClass() const \
		{ return RUNTIME_CLASS(class_name); }

4. IMPLEMENT_DYNAMIC

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
	IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL, NULL)

有了上面的幾個宏定義,現在只需要使用DECLARE_DYNAMIC IMPLEMENT_DYNAMIC兩個宏就可以使CObject的派生類擁有動

態識別的功能。

一個例子:向自己的類中添加動態類型識別的功能

class CPerson : public CObject
{
	//聲明支持動態類信息
	DECLARE_DYNAMIC(CPerson)
};

//實現動態類信息
IMPLEMENT_DYNAMIC(CPerson, CObject)

int main()
{
	CObject *pMyObject = new CPerson;
	if(pMyObject->IsKindOf(RUNTIME_CLASS(CPerson)))
	{
		CPerson * pMyPerson = (CPerson*)pMyObject;
		cout<<"a CPerson Object!\n";
		delete pMyPerson;
	}
	else
		delete pMyObject;
	return 0;
}

動態創建:建立在動態識別基礎之上

在動態識別的基礎上,向類裏面添加一個創建該類的靜態成員函數,就可以完成動態創建的功能了。依靠上面的兩個宏

(DECLARE_DYNAMIC IMPLEMENT_DYNAMIC), 可以很容易的定義出支持動態創建的一組宏,將它們命名爲

DECLARE_DYNCREATE IMPLEMENT_DYNCREATE。

1. DECLARE_DYNCREATE:

#define DECLARE_DYNCREATE(class_name) \
	DECLARE_DYNAMIC(class_name) \
	static CObject* PASCAL CreateObject();

2. IMPLEMENT_DYNCREATE:

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
	CObject* PASCAL class_name::CreateObject() \
		{ return new class_name; } \
	IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
		class_name::CreateObject, NULL)

怎麼使用?和動態類型識別宏的使用差不多,例如:

class CPerson : public CObject
{
	//聲明支持動態創建
	DECLARE_DYNCREATE(CPerson);
};

//實現動態創建
IMPLEMENT_DYNCREATE(CPerson, CObject)



 

 

 

 

 

發佈了37 篇原創文章 · 獲贊 16 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章