MFC 运行时类信息机制

目录

运行时类信息机制概述

测试

宏代换分析

结构体 CRuntimeclass

函数 GetRuntimeClass()

总结

执行过程分析


运行时类信息机制概述

在程序运行过程中可以获知对象的类的相关信息(例如∶对象是否属于某个类)

如何使用?

  • 类必须派生自CObject
  • 类内必须添加声明宏DECLARE_DYNAMIC( theClass )
  • 类外必须添加实现宏IMPLEMENT_DYNAMIC(theClass , baseClass)
     

当一个类具备上述三个要件后,CObject : : IsKindOf函数就可以正确判断对象是否属于某个类。

测试

创建一个控制台项目,使用MFC静态库

#include 
#include 
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 表示父类宏展开静态变量地址

MFC 运行时类信息机制_第1张图片

这也就相当于构成了一个链表

函数 GetRuntimeClass()

返回本类成员 CRuntimeClass 结构体成员的地址

CRuntimeClass* CDog::GetRuntimeClass() const
{
	//	return RUNTIME_CLASS(CDog); 
	return ((CRuntimeClass*)(&CDog::classCDog));
}

总结

classCDog静态变量:保存为类名和类大小等信息,以及父类静态变量地址(负责连接链表)

GetRuntimeClass()虚函数:获取本类的静态变量地址(获取链表头结点)

执行过程分析

过程总结如下:

  1. 利用对象( yellowdog )的地址调用宏展开的虚函数GetRuntimeClass()获取本类静态变量的地址(链表头)
  2. 利用本类静态变量的地址(链表头)和目标进行比对。
  3. 如果相同,证明对象属于这个类。
  4. 如果不相同获取链表的下一个结点(父类静态变量地址)循环比对,只要有一次相同也能证明对象属于这个类。循环结束一次都没有比对成功,证明对象不属于这个类。
     

设置断点分析,函数内部this指针是 yellowdog;参数是CWnd类的结构体的地址

MFC 运行时类信息机制_第2张图片

获取本类结构体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函数的结果

你可能感兴趣的:(MFC,mfc)