MFC运行时类信息机制及动态创建机制

《深入浅出MFC》书中DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏的详细解释 最近有些朋友在看《深入浅出MFC》的时候,被第三章的几个宏给卡住了,记得我第一次看此书时,也被这几个宏给卡住。当然真正卡人的其实是第一个,也就是DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC。我做了一个详解,供同样被卡住的朋友做个参考:)说明:这两个宏的主要目的,是在所指定的class(比如CView)的声明和实现里,加上一些静态成员函数和静态成员变量。所以,不要管“/”这个换 阅读详情

绪论

前面几篇文章解介绍了MFC的程序启动机制、窗口创建机制以及消息映射机制。今天将介绍MFC另外的两大机制运行时类信息机制和动态创建机制。
运行时类信息机制是动态创建的基础。动态创建机制是在运行时类信息机制的基础上实现的。运行时类信息机制就是知道对象属于那个类,就像我们C++使用的typeid运算子一样。
MFC的动态创建机制就是运行时类信息的结构的基础上动态的创建对象,接下来详细的介绍这两种机制。

运行时类信息机制(RTTI)

利用CObject::IsKindOf函数判断对象是否属于某个类

运行时类信息机制的使用

  1. 类必须派生自CObject

  2. 类内必须添加声明 DECLARE_DYNAMIC(theclass)

  3. 类外必须添加实现宏 IMPLEMENT_DYNAMIC(theclass,baseClass)

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

运行时类信息机制的实现原理

MFC是如何通过IsKindOf就可以知道一个对象是否属于一个类呢?

为了进一步研究,我们将创建几个具有继承关系的类,并按照运行时类信息机制的使用声明这几个宏,最后将这几个宏进行展开。

class CAnimal :pub1ic Cobject
{
   DECLARE_DYNAMIC(CAnima1)  //类内声明
   //DECLARE_DYNAMIC(CAnima1)的展开
 public:
   static const CRuntimeClass classCAnimal;
   virtual CRunt imeClass* GetRuntimeClass() const;
} 
//类外实现宏
  IMPLEMENT_DYNAMIC(CAnimal, Cobject)
// IMPLEMENT_DYNAMIC(CAnimal, Cobject)的展开是IMPLEMENT_RUNTIMECLASS宏

// IMPLEMENT_RUNTIMECLASS(CAnimal, Cobject, 0xFFF, NULL, NULL)
// IMPLEMENT_RUNTIMECLASS(c1ass_name, base_class_name,0xFFFF,NULL,NULL)展开
JAFX_ COMDAT const CRuntimeClass CAnimal: :classCAnimal = {
    "CAnimal",
    sizeof(class CAnima1),
    0xFFFF,
    NULL,
 // RUNTIME_CLASS(cobject),
//此处将RUNTIMB_CLASS(CObject)展开为_RUNTIMECLASS(class_name)
//再将RUNTIME_CLASS(c1ass_name)宏展开为
   ((CRuntimeClass*)(&CObject::classC0bject)),
    NULL,
    NULL 
}
CRuntimeClass* CAnimal::GetRuntimeClass() const
{
  return RUNTIME_CLASS(CAnimal);
}

将每个宏展开可知
在声明宏中有一个静态变量 static const CRuntimeClass classCAnimal;和一个获取静态变量的虚函数。
在实现宏中对静态变量进行赋值 和 对虚函数进行实现。接下来对CRuntimeClass这个结构进行分析

RuntimeClass数据结构简介

CRuntimeClass中不仅包含属性还包含一些函数,为了简化介绍,只介绍CRuntimeClass的属性

struct CRuntimeClass
{
   LPCSTR m_lpszClassName; //类名称
   int m_nObjectSize;      //类大小
   UINT m_wSchema;         //类版本(无用)
   CObject*(PASCAL* m_pfnCreateObject)(); //动态创建机制使用,这里为NULL
   CRuntimeClass* m_pBaseClass;   //父类宏展开静态变量地址
   CRuntimeclass* m_pNextClass; //不使用 为NULL
   const AFX_CLASSINIT* m_pClassInit; //不使用 为NULL
};

一个非常重要的宏RUNTIME_CLASS(theClass)

RUNTIME_CLASS(theClass) ----> &theClass::classtheclass; 获取thecClass这个类的静态变量classtheclass的地址

根据上面数据结构可知每一子类都会保存一个父类的静态变量,这样就会形成如下的根据继承关系形成的链表(类继承关系为CObject->CAnimal->CDog)

CDog
CRuntimeClass classCDog;
GetRuntimeClass()
CAnimal
CRuntimeClass classCAnimal;
GetRuntimeClass()
CObject
CRuntimeClass classObject;
GetRuntimeClass()
NULL
CRuntimeDog
.....
CAnimal::classAnimal
......
CRuntimeAnimal
.....
CAnimal::classCObject
......
CRuntimeObject
.....
CAnimal::classCObject
......

如上图所示,通过 RuntimeClass数据结构形成了一个与继承相关的链表。通过该链表可以判断该对象是否属于该类。它的执行过程如下:

运行时类信息机制执行过程

dog.IsKinnOf(RUNTIME_CLASS(CAnimal))
{
    CRuntimeClass* pClassThis = GetRuntimeClass(); //调用虚函数,获取头节点
    //利用IsDeriveFrom进行链表的遍历,是否能够找到与pClass相同的类,IsDeriveFrom的具体执行如下。
    return pClassThis->IsDeriveFrom(pClass);
                       {
                         const CRuntimeClass* pClassThis = this; //获取头节点
					    //进行循环遍历
					    while (pClass != NULL)
					    {
					        if (pClassThis == pClass)//判读与该父类对象是否相同
					        {
					            return true;
					        }
					        pClassThis = pClassThis->m_pBaseClass
					    }
					    return false;
                       }
}

总结:
执行过程如下

  1. 利用对象的地址调用宏展开的虚函数GetRuntimeClass()获取本类静态变量的地址(链表头)
  2. 利用本类静态变量地址(链表头)和目标进行比对
  3. 如果相同,证明对象属于这个类
  4. 如果不相同就会获取链表的下一个节点循环进行比对,一直到链表尾部。

动态创建机制

动态创建机制可以在不知道类名的情况下,将类的对象创建出来。但这个对象要有几个特征,接下来具体介绍一下。

动态创建机制的使用

类必须派生自CObject

类内必须添加声明宏 DECLARE_DYNCREATE (theClass)

类外必须添加实现宏 IMPLEMENT_DYCREATE(theClass,baseClass)

但一个类具备上述三个要件后,CRuntimeClass::CreateObject(对象加工厂)函数就可以将类的对象创建出来。

动态创建机制的原理

为了能够及更好的理解动态创建机制的原理,将上面的宏全部展开为

class CDog :public CAnimal
{
    //动态创建类内声明宏
    DECLARE_DYNCREATE (CDog)
    //DECLARE_ DYNCREATE (CDog)展开为
         DECLARE_DYNAMIC(CDog)
         static Cobject* PASCAL CreateObject();
    //DECLARE DYNCREATE中包含了运行时类信息机制的类内声明宏,将DECLARE_ DYNAMIC (CDog) 展开为
    public:
     static const CRuntimeClass classCDog ;
     virtual CRuntimeClass* GetRuntimeC1ass() const;
}

//动态创建机制类外实现宏
IMPLEMENT_DYNCREATE(CDog,CAnima1)
// IMPLEMENT_DYNCREATE(CDog, CAnimal)展开为
CObject* PASCAL CDog::Create0bject()
{
  return new CDog;
}
IMPLEMENT_RUNTIMECLASS(CDog,CAnimal, 0xFFFF,CDog::Create0bject, NULL)
//与运行时类信息机制相同该宏内也包含了IMPLEMENT_RUNTIMECLASS
//将IMPLEMENT_RUNTIMECLASS展开为
AFX_COMDAT const CRuntimeC1ass CDog::classCDog = {
    "CDog",
    sizeof (class CDog),
    0xFFF,
    CDog::Create0bject,
    RUNTIMECLASS(CAnima1),
    NULL,
    NULL
};
CRuntimeClass* CDog::GetRuntimeC1ass() const
{
    return RUNTIMECLASS (CDog);
}

动态创建机制与运行时类信息机制的区别

通过对动态创建机制和运行时类信息机制的宏展开可以得到动态创建机制与运行时类信息机制的区别:

  1. 多了一个静态函数

    CObject* PASCAL CDog::Create0bject()
    {
    return new CDog;
    }

  2. 静态变量的第四个成员不再为NULL,而为新增加的这个静态函数的地址CDog::Create0bject

动态创建机制的执行过程

通过与运行时类信息机制对比,动态创建机制与运行时类信息机制相同都维护这一个与继承关系相对应的链表。由此可知动态创建机制的执行过程如下:

  1. 利用本类(CDog)的静态变量CRuntimeClass调用其成员函数CreateObject(对象加工厂函数)
  2. 获取静态变量的第四个成员CreateObject(),并调用
  3. 在CreateObject();的内部,完成对象的创建,并返回对象的地址。

结语

运行时类信息机制和动态创建机制都是利用维护一个与继承关系相对应的链表。通过此链表来找到对应类的信息,从而获取类的信息与创建对象。MFC利用该机制可以在框架内部动态的创建视图类CView和CDocument,并将这两个类建立关系。运行时类信息机制和动态创建机制在MFC中的应用请观看我的下一篇文章MFC的视图类与文档类及其关系。

MFC关键技术模拟(5)------动态创建 1.什么是动态创建? 通俗的说,动态创建就是在程序运行时创建指定类的对象。MFC AppWizard创建的单文档程序中就动态创建了框架窗口对象、文档对象和视图对象。 2.动态创建的作用? 动态创建在程序需要的时候才会创建指定的类对象,这样用户就可以使用VC提供好的模版根据自己的需要生成相应的类,就不会多出没有用的对象了,节省了编译的时间。在MFC中动态创建应用很常见。 3动态创建 3.1 阅读详情

相关推荐

MFC CRuntimeClass 学习

CRuntimeClass 是一个在MFC中用于管理和存储有关类类型的信息的类;

bcbobo21cn的专栏 886

MFC 动态创建控件 字体设置问题

在mfc对话框上动态创建一个group box控件, 字体不好看,如下图: 代码如下: CButton *pCTGopBox=new CButton; pCTGopBox->Create(_T("静态"),WS_CHILD|WS_VISIBLE|BS_GROUPBOX , CRect(15,90,470,140,this,4000);   两种改变字体的方法: 1.先创建一种字体,

qingu的专栏 2182

手把手教你用Microsoft AEC Challenge数据集训练自己的回声消除模型(附完整代码)

本文详细介绍了如何使用Microsoft AEC Challenge数据集训练专业的回声消除模型,包括环境准备、数据清洗、模型架构设计、训练流程和实际部署注意事项。通过完整的代码示例和实战指南,帮助开发者快速掌握AEC技术,提升语音通信系统的回声消除效果。

weixin_27697385的博客 459

MFC(五)运行时类信息机制 动态创建机制 序列化机制

世上的事,会则不难,难则不会~ WIN32学习起来也并不简单,而到了MFC,框架6大机制相当复杂,学习就更加困难。 迎着困难向上~其实也就没有那么难了~...

AouSdu 1321

超详细Matlab R2021a免费安装教程(附安装包)

Matlab是一种高级技术计算语言和交互式环境,用于算法开发、数据可视化和数值计算。它集成了数学、工程和科学计算的丰富函数库,提供了强大的数据分析和绘图工具。Matlab还支持并行计算和大规模数据处理,适用于各种领域,如信号处理、图像处理、控制系统、机器学习等。

waicsdn_haha的博客 1万+

嵌入式Linux Qt应用程序卡死问题分析记录

根据应用和系统层面的分析,软件功能异常和卡死现象的原因是系统控制台/dev/console阻塞导致依赖其的相关应用和命令异常。系统控制台/dev/console阻塞的原因还未确定,最近的软件版本和其他测试同事未出现该问题,所以很大可能是串口线的问题,待后续有进展了继续更新。

V10_x的博客 1646

DECLARE_DYNAMIC

DECLARE_DYNAMIC 宏的含义  DECLARE_DYNAMIC(class_name)   说明:    但从CObject派生一个类时,此宏增加关于一个对象类的访问运行时间功能。把DECLARE_DYNAMIC宏加入类的头文件中,然后在全部需要访 问词类对象的.CPP文件中都包含此模块。如果像所描述那样使用DELCARE_DYNAMIC和IMPLEMENT_DYNAMIC宏,那么用户便可使 用RUNTIME_CLASS宏和CObject::IsKindOf函数以在运行时间决定对象类。如果DEC

lost_forget的专栏 6132

【backtrader保姆级教学】投资组合回测

method1:探索投资组合的最有方案,使用蒙特卡洛模拟Markowitz模型。# 提取最小波动组合对应的权重, 并转换成Numpy数组。# 绘制收益-标准差的散点图,并用颜色描绘夏普比率。# 在收益-风险散点图中突出风险最小的点。:param any_day: 任意日期。# 将该点坐标显示在图中并保留四位小数。password = “替换密码”# 找到标准差最小数据的索引值。user = “替换账号”# 计算GMV投资组合收益。# 计算每项资产的夏普比率。# 设置无风险回报率为0。

weixin_38132951的博客 2315

二、C++、DECLARE_DYNAMIC与IMPLEMENT_DYNAMIC宏

DECLARE_DYNAMIC:声明“运行时类型识别”宏,存在于.h文件中 语法:DECLARE_DYNAMIC(派生类) IMPLEMENT_DYNAMIC:实现“运行时类型识别”宏,存在于.cpp文件中 语法:DECLARE_DYNAMIC(派生类,基类) 作用:使得在MFC框架下能够运行所建的派生类,此派生类继承于MFC中的基类 ...

ARM_qiao的博客 4132

一张图讲透银行个人外汇业务逻辑和实操

个人外汇业务主要分为结售汇和外币兑换两类,前者满足日常跨境需求,后者因投机属性多数银行已暂停。业务核心是利用汇率波动实现货币兑换,满足支付或投资需求。交易涉及客户分类、主流币种、多种渠道和汇率计算规则,需区分直接/间接标价法判断汇率走势。银行通过"货币兑换"科目核算损益,采用期末折算确认盈亏。监管要求包括5万美元年度额度、合法渠道、真实性原则及大额申报等。随着跨境金融数字化发展,掌握基础逻辑和合规要求是安全参与外汇业务的关键。

银行信息系统应用架构详解 289

基于MATLAB的最大重叠离散小波变换(MODWT)算法详解

最大重叠离散小波变换(Maximal Overlap Discrete Wavelet Transform, MODWT)是DWT的重要改进形式,由Percival和Walden等人在20世纪90年代系统提出并完善。MODWT通过消除下采样操作,采用样本平移不变的分解方式,解决了DWT的多个固有缺陷。MODWT的核心创新在于取消下采样环节。与DWT每级分解后对滤波输出进行二分下采样不同,MODWT在每一级都使用相同的滤波器,但通过插入零值的方式调整滤波器系数,保持每级系数数量与原始信号相同。

qq_42212808的博客 115

【上位机——MFC】运行时类信息机制

【上位机——MFC】运行时类信息机制

weixin_39723539的博客 473

基于Xilinx XDMA 的PCIE通信

基于Xilinx XDMA 的PCIE通信 概述:   想实现基于FPGA的PCIe通信,查阅互联网各种转载…基本都是对PCIe的描述,所以想写一下基于XDMA的PCIe通信的实现(PCIe结构仅做简单的描述(笔记),了解详细结构移至互联网)。实践实践!!! 说明: 参考文档: PCI Express Base Specification Revision 3.0 PCI Express Base Specification Revision 5.0 pg195-pcie-dma PCI Express体系

Crazzy_M的博客 1万+

MFC六大机制(五)动态创建机制

一、作用:动态创建对象 二、使用 1、必须直接或间接继承CObject类 2、类内添加声明宏DECLARE_DYNCREATE(CDog) 3、类外添加实现宏DECLARE_DYNCREATE(CDog, CAnimal) 三、具体实例 1 class CAnimal : public CObject 2 { 3 DECLARE_DYNCREATE(CAnimal...

weixin_30235225的博客 272

粒子群算法Particle Swarm Optimization超详细解析+代码实例讲解

粒子群算法,也称粒子群优化算法或鸟群觅食算法(Particle Swarm Optimization),缩写为 PSO, 是近年来由J. Kennedy和R. C. Eberhart等开发的一种新的进化算法(Evolutionary Algorithm - EA)。

猫敷雪 893

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

CObject 类

CObject类 CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。 本章将讨论MFC如何设计CObject类的这些特性。首先,考察CObjec

完志驿站 1824

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

MFC---C++

MFC

Major_S的博客 556

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

5.MFC基础(五)视图、运行时类信息、动态创建

一、MFC的视图窗口  1.相关问题    视图窗口:提供了一个用于显示数据的窗口,并和用户进行交互操作  2.相关的类    CView及其子类 - 父类CWnd,封装了关于视图窗口的操作  3.视图窗口的使用   (1)从CView类派生一个自己的视图类(CMyView),并必须重写父类的纯虚函数OnDraw      当CView类帮我们处理WM_PAINT消息时将调...

diandao9056的博客 307

MFC程序设计(八)动态创建机制

这两种方法都需要直到类名才可以创建在不知道类名的情况下,就需要依靠动态创建机制来创建对象了。实际上这有点吹,还是需要知道类名的在实际中,我们常见的创建对象的方法是我们自己创建的,而通过这种方法创建的对象是让MFC自己创建的。

2301_78838647的博客 640

剖析以及实现MFC核心机制(CObject)

注:本篇文章依赖于网上一篇对CObject功能分析的文章(后来才知道是一本书上的),我对其做了进一步详细的注释,一方面使其文章思路更加清晰,一方面又对其中论述进行补充(以我本人的观点看起来觉得不充分详细的地方),最后对其文章中机理分析予以实现(实现CObject),其中加注部分为我新增的理解! CObject类 CObject是大多数MFC类的根类或基类。CObject类有很多有用的特...

Jack Zheng's Blog 900

MFC架构之CObject类

<br />      CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。<br />     本文讨论MFC如何设计CObject类的这些特性。首先,考察CObject类的定义,分析其结构和方法(成员变量和成员函数)对CObject特性的支持。然后,讨论CObje

FlowShell的专栏 3485

MFC仿真

本文是《深入浅出MFC》第三章的读书笔记。

静下心来,做好每一件事 692

mfc第五天

一MFC视图     1,相关问题     视图窗口    --一个数据的窗口,可以喝用户进行交互操作     MFC视图类CView及其子类     2.视图窗口的使用            框架窗口带标题栏,是父窗口,而视图窗口不带标题栏,是子窗口     2.1将CView类派生自己的视图类(CMyView),并需要重写一个虚函数OnDraw     在框架窗口的WM_CREAT

jinya 621

CObject类

CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。 CObject的结构 class CObject{public://与动态创建

armman的专栏 1515

CObject类学习

 CObject类 CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。本章将讨论MFC如何设计CObject类的这些特性。首先,考察C

1575
上一篇: MFC的消息处理与消息映射机制
♚陌路,相逢☜
博客等级 码龄8年 21粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值