运行时 类型识别RTTI
struct CRuntimeClass
{
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; //框架编号
Cobject * (PASCAL * m_pfnCreateObject){};
CRuntimeClass * m_pBaseClass;
static CRuntimeClass * pFirstClass; //类型链表头指针
CRuntimeClass * m_pNextClass;
}
我们希望,每一个类都有这样一个CRuntimeClass的成员变量,并且最好有一定的命名规则,然后经某种手段将整个类库建构好之后,能呈现类似的风貌:
DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC宏
为了神不知鬼不觉吧CRuntimeClass对象塞进类之中,并声明一个可以抓到该对象的地址函数,我们定义DECLARE_DYNAMI宏如下:
#define DECLARE_DYNAMIC (class name)\
public: \
static CRtimeClass class##classname;\
virtual CRuntimeClass* GetRuntimeClass() const;
出现##的地方,用来告诉编译器,把这两个字符串系在一起。例如:
DECLARE_DYNAMIC(CView)
则编译器为你实现的代码如下:
public:
static CRuntimeClass classCView;
virtual CRuntimaClass* GetRuntimeClass() const;
这样子只要在声明的时候放入DECLARE_DYNAMIC宏看似万事OK,
我们类别型录(CRunTimeClass)的内容对象指定以及连接工作最好也能神不知鬼不觉,于是乎定义了IMPLEMENT_DYNAMIC宏:
#define IMPLEMENT_DYNAMIC(class_name,base_class_name)\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
其中_IMPLEMENT_RUNTIMECLASS又是一个宏。如下:
#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
static char _lpsz##class_name[]=#class_name;\
CRuntimeClass class_name::class##class_name={\
_lpsz##class_name,sizeof(class_name),wSchema,pfnNew,\
RUNTIEM_CLASS(base_class_name),NULL};\
static AFX_CLASSSINIT _init_##class_name(&class_name::class##class_name);\
CRuntimeClass * class_name::GetRuntimeClass() const \
{return &class_name::class##class_name;}\
其中又有RUNTIME_CLASS宏定义如下:
#define RUNTIME_CLASS(class_name) \
(&class_name::class##class_name)
这样看起来IMPLEMENT_DYNAMIC内容好像只指定初值,其实不然,其美妙在于它使用了一个struct AFX_CLASSINIT,定义如下:
struct AFX_CLASSINIT
{
AFX_CLASSINIT (CRuntimeclass* pNewClass);
};
这是标准的构造函数,定义如下:
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass *pNewClass)
{
pNewClass->m_pNextClass =CRuntimeClass::pFirstClass;
CRuntimeClass::pFirst=pNewClass;
}
很明显构造函数负责把linked list连接起来。
整个宏看起来很吓人,看一个例子: