目录
运行时类信息机制概述
测试
宏代换分析
结构体 CRuntimeclass
函数 GetRuntimeClass()
总结
执行过程分析
运行时类信息机制概述
在程序运行过程中可以获知对象的类的相关信息(例如∶对象是否属于某个类)
如何使用?
- 类必须派生自CObject
- 类内必须添加声明宏DECLARE_DYNAMIC( theClass )
- 类外必须添加实现宏IMPLEMENT_DYNAMIC(theClass , baseClass)
当一个类具备上述三个要件后,CObject : : IsKindOf函数就可以正确判断对象是否属于某个类。
测试
创建一个控制台项目,使用MFC静态库
#include <afxwin.h>
#include <iostream>
using namespace std;
class CAnimal : public CObject {
DECLARE_DYNAMIC(CAnimal)
};
IMPLEMENT_DYNAMIC(CAnimal, CObject)
class CDog : public CAnimal {
DECLARE_DYNAMIC( CDog )
};
IMPLEMENT_DYNAMIC( CDog, CAnimal )
int main() {
CDog yellowdog;
if (yellowdog.IsKindOf(RUNTIME_CLASS(CWnd))) {
cout << "yellowdog is CWnd" << endl;
}
else {
cout << "yellowdog isnot CWnd" << endl;
}
return 0;
}
宏代换分析
DECLARE_DYNAMIC( CDog )
代换为
第一个是结构体,第二个是一个虚函数,用来获取本类的结构体的地址
public:
static const CRuntimeClass classCDog;
virtual CRuntimeClass* GetRuntimeClass() const;
IMPLEMENT_DYNAMIC( CDog, CAnimal )
代换为
IMPLEMENT_RUNTIMECLASS(CDog, CAnimal, 0xFFFF, NULL, NULL)
代换为
AFX_COMDAT const CRuntimeClass CDog::classCDog = {
"CDog",
sizeof(class CDog),
0xFFFF,
NULL,
// RUNTIME_CLASS(CAnimal),
((CRuntimeClass*)(&CAnimal::classCAnimal)),
NULL,
NULL
};
CRuntimeClass* CDog::GetRuntimeClass() const
{
// return RUNTIME_CLASS(CDog);
return ((CRuntimeClass*)(&CDog::classCDog));
}
结构体 CRuntimeclass
这个结构体主要关注第 1,2,4,5即可
struct CRuntimeClass
{
LPCSTR m_lpszClassName; // 类名称
int m_nObjectSize; // 类大小
UINT m_wSchema; // 类版本,固定值,0xFFFF
CObject* (PASCAL* m_pfnCreateObject)(); // 动态创建机制使用,这里为NULL
CRuntimeClass* m_pBaseClass; // 父类宏展开静态变量地址
CRuntimeClass* m_pNextClass; // 不适用为NULL
const AFX_CLASSINIT* m_pClassInit; // 不适用为NULL
}
属性 5 表示父类宏展开静态变量地址
这也就相当于构成了一个链表
函数 GetRuntimeClass()
返回本类成员 CRuntimeClass 结构体成员的地址
CRuntimeClass* CDog::GetRuntimeClass() const
{
// return RUNTIME_CLASS(CDog);
return ((CRuntimeClass*)(&CDog::classCDog));
}
总结
classCDog静态变量:保存为类名和类大小等信息,以及父类静态变量地址(负责连接链表)
GetRuntimeClass()虚函数:获取本类的静态变量地址(获取链表头结点)
执行过程分析
过程总结如下:
- 利用对象( yellowdog )的地址调用宏展开的虚函数GetRuntimeClass()获取本类静态变量的地址(链表头)
- 利用本类静态变量的地址(链表头)和目标进行比对。
- 如果相同,证明对象属于这个类。
- 如果不相同获取链表的下一个结点(父类静态变量地址)循环比对,只要有一次相同也能证明对象属于这个类。循环结束一次都没有比对成功,证明对象不属于这个类。
设置断点分析,函数内部this指针是 yellowdog;参数是CWnd类的结构体的地址
获取本类结构体CRuntimeClass的地址
CRuntimeClass* pClassThis = GetRuntimeClass();
调用函数IsDerivedFrom(pClass);参数是CWnd类的结构体CRuntimeClass的地址,this指针是yellowdog的结构体CRuntimeClass地址
return pClassThis->IsDerivedFrom(pClass);
如果两者相等返回TRUE
if (pClassThis == pBaseClass)
return TRUE;
就一直循环获取父类宏展开静态变量地址,也就是父类的CRuntimeClass结构体
直到遍历到CObject类,它的CRuntimeClass结构体属性5是NULL
否则,就返回FALSE,也就是isKindOf函数的结果