CObject与CRuntimeClass(转)

CObject和CRuntimeClass是MFC中两个非常重要的类/结 构,绝大部分MFC类都是以CObject做为基类, CRuntimeClass结构同CObject密不可分,了解它们对于深入理解MFC具有重要意义。 

Returns the CRuntimeClass structure corresponding to this object's class.

virtual CRuntimeClass* GetRuntimeClass( ) const;

Return Value

A pointer to the CRuntimeClass structure corresponding to this object's class; never NULL.

Remarks

There is one CRuntimeClass structure for each CObject-derived class. The structure members are as follows:

  • LPCSTR m_lpszClassName   A null-terminated string containing the ASCII class name.
  • int m_nObjectSize   The size of the object, in bytes. If the object has data members that point to allocated memory, the size of that memory is not included.
  • UINT m_wSchema   The schema number ( – 1 for nonserializable classes). See the IMPLEMENT_SERIAL macro for a description of schema number.
  • CObject* ( PASCAL* m_pfnCreateObject )( )   A function pointer to the default constructor that creates an object of your class (valid only if the class supports dynamic creation; otherwise, returns NULL).
  • CRuntimeClass* ( PASCAL* m_pfn_GetBaseClass )( )   If your application is dynamically linked to the AFXDLL version of MFC, a pointer to a function that returns the CRuntimeClass structure of the base class.
  • CRuntimeClass* m_pBaseClass   If your application is statically linked to MFC, a pointer to the CRuntimeClass structure of the base class.

This function requires use of the IMPLEMENT_DYNAMIC, IMPLEMENT_DYNCREATE, or IMPLEMENT_SERIAL macro in the class implementation. You will get incorrect results otherwise.

Example

See CObList::CObList for a listing of the CAge class used in all CObject examples.

// example for CObject::GetRuntimeClass
CAge a(21);
CRuntimeClass* prt = a.GetRuntimeClass();
ASSERT( strcmp( prt->m_lpszClassName, "CAge" )  == 0 );

See Also


CRuntimeClass Members

Data Members

m_lpszClassName The name of the class.
m_nObjectSize The size of the object in bytes.
m_pBaseClass A pointer to the CRuntimeClass structure of the base class.
m_pfnCreateObject A pointer to the function that dynamically creates the object.
m_pfnGetBaseClass Returns the CRuntimeClass structure (only available when dynamically linked).
m_wSchema The schema number of the class.

Operations

CreateObject Creates an object during run time.
FromName Creates an object during run time using the familiar class name.
IsDerivedFrom Determines if the class is derived from the specified class.

一、CRuntimeClass结构
要 理解CObject,我们先来看一下CRuntimeClass这个在MFC中至关重要的一个结构。
每个从CObject中派生的类都有有一个 CRuntimeClass对象同它关联以完成在运行时得到类实例的信息或者是它的基类。 在afx.h中它的定义如下: 
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName; //类名,一般是指包含CRuntimeClass对象的类的名称
int m_nObjectSize; //包含CRuntimeClass对象的类sizeof的大小,不包括它分配的内存
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

// 以上m_pBaseClass的指针(函数)是MFC运行时确定类层次的关键,它一个简单的单向链表

// Operations
CObject* CreateObject(); //这个函数给予CObject 派生类运行时动态建立的能力
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

//这个函数使用 m_pBaseClass或 m_pfnGetBaseClass遍历整个类层次确定是否pBaseClass指向的类是基类,
//使用它可以判 断某类是否是从pBaseClass指向的类在派生来。

// 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
};



二、CObject类
CObject 是MFC类的大多数类的基类,主要是通过它实现:
(1)、运行类信息;(2)、序列化;(3)、对象诊断输出;(4)、同集合类相兼容;
(1)、 运行时类信息:
注意:要想使用CRuntimeClass结构得到运行时类信息,你必须在你的类中包括 DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC、 DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE或DECLARE_SERIAL/IMPLEMENT_SERIAL。但你 的类必须是从CObject派生的才能使用这些宏, 因为通过DECLARE_DYNAMIC将定义一个实现如下的函数: 
CRuntimeClass* PASCAL B::_GetBaseClass()

return RUNTIME_CLASS(base_name); 
}

其 中的RUNTIME_CLASS是这样定义的 
#define RUNTIME_CLASS( class_name ) /
(CRuntimeClass *)(&class_name::class##class_name);

即得到类中的CRuntimeClass对象指针, 显而易见,如果没有基类你用IMPLEMENT_DYNAMIC时将得到一个编译错误。 除非你象CObject一样不用DECLARE_DYNAMIC而定义和实现了这些函数,CObject中的GetBaseClass只是简单的返回 NULL。 实际的DECLARE_DYNAMIC在afx.h中声明如下: 
#define DECLARE_DYNAMIC(class_name) /
protected: /
static CRuntimeClass* PASCAL _GetBaseClass(); /
public: /
static const AFX_DATA CRuntimeClass class##class_name; /
virtual CRuntimeClass* GetRuntimeClass() const; /


IMPLEMENT_DYNAMIC在afx.h中定义如下: 
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) /
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) /
CRuntimeClass* PASCAL class_name::_GetBaseClass() /
{ return RUNTIME_CLASS(base_class_name); } /
AFX_COMDAT const AFX_DATADEF CRuntimeClass class_name::class##class_name = { /
#class_name, sizeof(class class_name), wSchema, pfnNew, /
&class_name::_GetBaseClass, NULL }; /
CRuntimeClass* class_name::GetRuntimeClass() const /
{ return RUNTIME_CLASS(class_name); } /

其中的CRuntimeClass* GetRuntimeClass() const;被定义为虚函数,以完成在类层次上的重载。 这也是MFC利用多态实现运行时动态类信息的方法。
另 外两个DECLARE_DYNCREATE和DECLARE_SERIAL类似。只不过它们多定义和实现了一些函数,对于使用 DECLARE_DYNCREATE 要注意的是类必须要有一个无参数的缺省构造函数,因为在DECLARE_DYNCREATE中定义了一个CreateObject函数 用以在动态的建立对象,它只是一条简单的return new class_name。
我们先来看一下序列化:
,CObject实现这些 功能绝大部分是通过它里面的CRuntimeClass对象classObject实现的, 
CObject不支持多重继承,即表示以 CObject为基类的类层次中只能有一个CObject基类。

之所以会这样,就是因为CRuntimeClass对象的成员 m_pBaseClass的关系。因为它只是一个单链表。
以下是它在afx.h中的定义: 
/////////////////////////////////////////////////////////////////////////////
// class CObject is the root of all compliant objects

#ifdef _AFXDLL
class CObject
#else
class AFX_NOVTABLE CObject
#endif
{
public:


// Object model (types, destruction, allocation)

virtual CRuntimeClass* GetRuntimeClass() const; 

// 上面的函数的实现只是很简单的return RUNTIME_CLASS(classObject);

virtual ~CObject(); // 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);
#if _MSC_VER >= 1200
void PASCAL operator delete(void* p, void* pPlace);
#endif

#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);
#if _MSC_VER >= 1200
void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine);
#endif
#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 AFX_DATA CRuntimeClass classCObject;
#ifdef _AFXDLL
static CRuntimeClass* PASCAL _GetBaseClass();
#endif
};

如果你在你的类的实现和定义中使用可选宏的其中一个,你必须了解从 CObject派生的好处。
第一级的宏是DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC,它允许你在运行时处理类名和类层 次中的位置,允许你做有意义的诊断Dump。
第二级的宏是DECLARE_SERIAL/IMPLEMENT_SERIAL,它包括第一级宏所有 的功能,允许你进行对象的序列化。 

要想彻底了解序列化,不得不了解Archive类,我们将在下回详细论述这个类。希望感兴趣的朋友同 我联系共同进步。 

你可能感兴趣的:(object,Class,mfc,pascal,Constructor,structure)