MFC RTTI,DYNCREATE,SERIAL 技术相关宏分析
使用 MFC 的 RTTI 先直接或者间接从 CObject 类派生自己的类,如下 :
===============================================================================
class MyClass : public CWnd{
int a;
public:
DECLARE_DYNMAIC(MyClass);
};
INPLEMENT_DYNMIC(MyClass,CWnd);
MyClass t;
if(t.IsKindOf(RUNTIME_CLASS(CObject)))
MessageBox(NULL,"fdk","fdkf",MB_OK);
===============================================================================
一: DECLARE_DYNMAIC(MyClass) 的宏扩展:
#ifdef _AFXDLL // 动态链接版
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
#define _DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
#else // 静态链接版
#define DECLARE_DYNAMIC(class_name) \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
#define _DECLARE_DYNAMIC(class_name) \
public: \
static AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
#endif
这里我们只分析动态链接版的:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
于是:
class MyClass : public CWnd{
int a;
public:
DECLARE_DYNMAIC(MyClass);
};
扩展为:
class MyClass : public CWnd{
int a;
public:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
static const AFX_DATA CRuntimeClass classMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
};
===============================================================================
二: INPLEMENT_DYNMIC(MyClass,CWnd) 的宏扩展:
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
#ifdef _AFXDLL // 动态链接版
#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); } \
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
CRuntimeClass* PASCAL class_name::_GetBaseClass() \
{ return RUNTIME_CLASS(base_class_name); } \
AFX_COMDAT 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); } \
#else // 静态链接版
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
AFX_COMDAT const AFX_DATADEF CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL }; \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return RUNTIME_CLASS(class_name); } \
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
AFX_DATADEF CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL }; \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return RUNTIME_CLASS(class_name); } \
#endif
这里我们选 "动态链接"版的:
#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); } \
INPLEMENT_DYNMIC(MyClass,CWnd) 宏扩展后为(为了便于分析格式经过纠正):
CRuntimeClass* PASCAL class_name::_GetBaseClass() {
return RUNTIME_CLASS(CWnd);
}
AFX_COMDAT const AFX_DATADEF CRuntimeClass MyClass::classMyClass = {
"MyClass", sizeof(class MyClass),
0xFFFF, NULL, &MyClass::_GetBaseClass, NULL
};
CRuntimeClass* class_name::GetRuntimeClass() const {
return RUNTIME_CLASS(MyClass);
}
===============================================================================
于是:
class MyClass : public CWnd{
int a;
public:
DECLARE_DYNMAIC(MyClass);
};
INPLEMENT_DYNMIC(MyClass,CWnd);
MyClass t;
if(t.IsKindOf(RUNTIME_CLASS(CObject)))
MessageBox(NULL,"fdk","fdkf",MB_OK);
扩展为 :
class MyClass : public CWnd{
int a;
public:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
static const AFX_DATA CRuntimeClass classMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
};
CRuntimeClass* PASCAL class_name::_GetBaseClass() {
return RUNTIME_CLASS(CWnd);
}
AFX_COMDAT const AFX_DATADEF CRuntimeClass MyClass::classMyClass = {
"MyClass", sizeof(class MyClass),
0xFFFF,NULL, &MyClass::_GetBaseClass, NULL
};
CRuntimeClass* class_name::GetRuntimeClass() const {
return RUNTIME_CLASS(MyClass);
}
MyClass t;
if(t.IsKindOf(RUNTIME_CLASS(CObject)))
MessageBox(NULL,"fdk","fdkf",MB_OK);
===============================================================================
上面还有宏: RUNTIME_CLASS 该宏的定义为
#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
于是RUNTIME_CLASS(CWnd) 扩展为: ((CRuntimeClass*)(&MyClass::classMyClass))
到这里应该亮一下 : CRuntimeClass 结构了
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;
// 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
};
// 我们这里用动态版的及为:
truct CRuntimeClass
{
LPCSTR m_lpszClassName; // 类名
int m_nObjectSize; // 类大小
UINT m_wSchema; // 版本,是否可以 serial
CObject* (PASCAL* m_pfnCreateObject)(); // 函数指针,用于DYNCREATE
CRuntimeClass* (PASCAL* m_pfnGetBaseClass)(); // 函数指针,取父类的结构体
CRuntimeClass* m_pNextClass; // 链接下一个结构体
// 下面的都是函数了
CObject* CreateObject();
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
void Store(CArchive& ar) const;
static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
};
===============================================================================
好了分析完了,最终的扩展结果是这样的: { 添加了点注释 }
===============================================================================
class MyClass : public CWnd{
int a;
public:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
static const AFX_DATA CRuntimeClass classMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
};
CRuntimeClass* PASCAL class_name::_GetBaseClass() {
// 返回指向父类的 CRuntimeClass 结构体指针
return (CRuntimeClass*)(&MyClass::classMyClass);
}
// 填充 CRuntimeClass 结构体,共六个数据成员,这里因为是结构体
// 数据成员都是 public 的,因此可以直接填充...
AFX_COMDAT const AFX_DATADEF CRuntimeClass MyClass::classMyClass = {
"MyClass", sizeof(class MyClass),
0xFFFF, NULL, &MyClass::_GetBaseClass, NULL
};
CRuntimeClass* class_name::GetRuntimeClass() const {
// 返回指向 MyClass 类数据成员 classMyClass 的指针
return (CRuntimeClass*)(&MyClass::classMyClass);
}
MyClass t; // IsKingOf() 是 CObject 类的成员,在 CObject 里实现
if(t.IsKindOf(((CRuntimeClass*)(&CObject::classCObject)))
MessageBox(NULL,"fdk","fdkf",MB_OK);
相信这些代码大家能够理解,我个人认为有必要弄懂这些宏,知道了 RTTI ,其它的那两个就
非常容易理解了.......
江南孤峰 ///////// 2007--11--16
评论