MFC 运行时类信息机制

目录

运行时类信息机制概述

测试

宏代换分析

结构体 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()虚函数:获取本类的静态变量地址(获取链表头结点)

执行过程分析

过程总结如下:

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

设置断点分析,函数内部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函数的结果

相关推荐

  1. C#获取当前运行环境信息

    2023-12-26 15:16:03       55 阅读
  2. 运行类型信息 typeid、type_info...(C++)

    2023-12-26 15:16:03       57 阅读
  3. 编程语言的运行和垃圾回收机制概览

    2023-12-26 15:16:03       55 阅读
  4. 【面试宝藏】Go语言运行机制面试题

    2023-12-26 15:16:03       31 阅读
  5. 程序运行,常见存储区分及作用

    2023-12-26 15:16:03       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-26 15:16:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-26 15:16:03       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-26 15:16:03       82 阅读
  4. Python语言-面向对象

    2023-12-26 15:16:03       91 阅读

热门阅读

  1. Nginx之Tengine主动健康检查解读

    2023-12-26 15:16:03       53 阅读
  2. 识别pdf标题并重命名pdf

    2023-12-26 15:16:03       63 阅读
  3. 010editor 模板位段

    2023-12-26 15:16:03       54 阅读
  4. Qt处理鼠标滚轮事件,放大缩小地图

    2023-12-26 15:16:03       70 阅读
  5. PHP面向对象基础之类、对象和基本特点

    2023-12-26 15:16:03       53 阅读