MFC动态创建(dynamic creation)实现原理_聪明的笨蛋的博客-程序员宝宝_mfc动态创建的原理

技术标签: # 2.2) C++  

在用到MFC的文档视图构架你可能有个非常迷惑的地方.就是很多类不知道在哪里就被莫名其妙的实例化了.

以单文档视图为例.代码中你能看到的的实例化的地方就只有两个一个是CWinApp的一个全局变量的实例化,另一个就是
CSingleDocTemplate 实例化.它的构造函数如下

CSingleDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,

CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);

然后接下来的事就你迷惑了,先是继承自SingleDocTemplate的类实例化了继承自CFrameWnd的类和继承自CDocument的类,然后呢继承自CFrameWnd的类又实例化了继承自CView的类.

你可能会想到背后早有写好的代码去实例化这些类了,但是最令你疑惑的是我自己定义继承自啥CView,CDocument等类的类时名字是自己随便取的啊,之前写好的代码竟然能有未卜先知的能力知道这类名? 不然不知道一个类的类名怎么去实例化它啊?

MFC自然没这么神奇的能力.所以毫无疑问的一点是你定义的新类类名信息肯定会传到某个地方,然后在那里实例化该类.背后的机制咋样的呢?

这就是所谓的动态生成(dynamic creation)机制了啊.该机制有用到前面讲的RTTI,在RTTI的基础上再扩充一些功能.

 

动态创建的一个简单例子

1.CRuntimeClass的定义

首先CRuntimeClass定义中除了RTTI信息,添加

struct CRuntimeClass{

CObject* ( *m_pfnCreateObject)(); //函数指针,指向的函数中会通过new实例化一个对象

CObject* CreateObject()

//其他信息省略掉了

}

其中函数CreateObject定义如下

CObject* CRuntimeClass::CreateObject(){

CObject* pObect = NULL;

pObject =(*m_pfnCreateObject)();

}

 

2.宏DECLARE_DYNCEATE

假如定义一个继承自CDocument的类CMyDoc.

我们瞧下CSingleDocTemplate* pTmp = new(.... RUNTIME_CLASS(CMyDoc) ....) //这里忽略其他参数.

CMyDoc是怎么被创建的呢? 先看CMyDoc定义中的宏

 

CMyDoc头文件//

DECLARE_DYNCEATE(CMyDoc)

///

相当于:

static CObject* CreateObject();

static CRuntimeClass classCMyDoc;

 

宏定义:

#define DECLARE_DYNCREATE(class_name) \

DECLARE_DYNAMIC(class_name) \

static CObject*  CreateObject();

 

3.宏IMPLEMENT_DYNCREATE

///CMyDoc cpp文件/

IMPLEMENT_DYNCREATE(CMyDoc, CDocument)

/

上面的宏除了前面的RTTI信息外,还有个

CObject*  CMyDoc::CreateObject(){

return new CMyDoc;

}

CMyDoc::classCMyDoc.m_pfnCreateObject = CMyDoc::CreateObject;

 

宏定义:

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \

CObject* class_name::CreateObject() \

{ return new class_name; } \

//IMPLEMENT_RUNTIMECLASS(......)//为讨论方便这里省略掉了

 

4.创建对象

有了上面两个宏,然后CSingleDocTemplate的构造函数中有个参数RUNTIME_CLASS(CMyDoc),我们知道

#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())

的以传的参数实际上是一个指向CMyView中的static CRuntimeClass classCMyDoc的指针.

于是可以这样调用函数创建对象

CObject* pDoc = RUNTIME_CLASS(CMyDoc)->CreateObject();//实际上就是调用

CObject* CMyDoc::CreateObject(){

return new CMyDoc;

}

 

 

总结:

你可能看到上面一堆乱七八糟的东东,就想着真他妈扯蛋啊,搞到最后不就是只需要一个类的名字,然后用该名字来实例化一个类嘛.有必要搞得这么麻烦嘛

该功能说起来简单,但实现起来还真没其他简单方法啊,除非C++语法做些更改,编译器添加些额外支持.我们知道函数中可以随便传个啥参数.

但实例化一个类比如CView* view = new CView; //一个类的名字是不能做为参数的啊.

比如void CreateObject(string className){

className* view = new className;

}

这样的函数绝对无法通过编译的.但我们上面讲到的貌似是这样实现的.因为那是宏,只是简单的文字替换,宏的替换那一步还没有轮到编译器去干活.宏替换完了才是编译器上场.

有了宏可以把类名当"参数"一样用可以说实现了一大半功能了.实际上你如果只是通过前面的两个宏整出一个静态函数static CObject* CreateObject();完全就可以了.但这样显然实现的不够优雅嘛,并且既然有个CRuntimeClass了就干脆把动态创建对象的函数带到该结构体中岂不更好啊(很多地方都用到CRuntimeClass,动态类型识别,动态创建,序列化).

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weiwenhp/article/details/8683245

智能推荐

已解决:maven,SSM项目的spring-mvc.xm文件引用类爆红:The fully qualified name of the bean's class, except if it serv_qq_33802316的博客-程序员宝宝

报错:The fully qualified name of the bean's class, except if it serves only as a parent definition for  child bean definitions.尝试maven搭建项目的时候,在spring-mvc.xml文件中引用类报错,网上找了一圈也没有找到方法。解决方法:原来就是因为不

android 实现textView 文本第一行开头嵌套图片,或者圆角TextView的实现思路_好个李先生的博客-程序员宝宝

最近项目要实现一个需求这种效果,黄色背景有圆角,字体内容会变化,首先想到的是用ImageSpan之类的来实现,可是找了好多没找到,无意之间想到可以自己写个自定义View来实现呀。于是思路就是黄色背景的是一个TextView A可以自己画圆角,第一行的“考上北京大学的经验!考上北京”一个TextView B,“大学的经验”一个TextView C即可实现。String textString = "考...

Robotframework+selenium+ride自动化框架搭建(Mac)_dou_being的博客-程序员宝宝

前段时间在学习robot framework + selenium + ride自动化测试框架,今天腾出一些时间总结一下学习该框架的第一步-框架的搭建,对该框架的使用总结持续进行。因为我使用的是Mac,所以以下搭建过程以Mac的搭建为例。首先,安装python3.7,安装成功后,配置环境变量: open ~/.bash_profile PATH=“/Library...

Linux之监控磁盘IO_weixin_34208283的博客-程序员宝宝

2019独角兽企业重金招聘Python工程师标准>>> ...

linux任何用户ssh正确密码登陆均报错Permission denied, please try again.处理方法,linux限制root直登后普通用户输入正确密码提示密码错误处理方法。_/*守护她的笑容的博客-程序员宝宝_linux密码对的却说密码错误

文章目录说明报错日志内容查看secure日志查看【知道就行】messages日志查看【这里面有记录】处理方法key文件删除修改配置文件中的UsePAM上面步骤过程测试自己可以ssh自己了工具也可以正常连接了别的服务器ssh自己【必看】说明我的一台虚拟机IP是:192.168.59.133出问题了,任何服务器使用任何用户ssh均报错,甚至连自己都不能ssh自己。也不能使用任何工具连接上该服务器,报错如下ssh报错如下任何服务器ssh报错内容均一样:报错内容均为:Permission d

SCSI与USB的关系_Swell_Fish的博客-程序员宝宝_usb scsi

SCSI与USB的关系由于BusHound在使用过程中,直接把USB和SCSI混为一谈,相关设计的时候这些东西也经常放在一起来讲,导致稍微缺乏经验的人傻傻分不清楚。因此在这里特别说明一下SCSI和USB分别是什么东西,以及他们是怎么联系在一起的。一、USB概述简介通用串行总线 (Universal Serial Bus,USB) 是一种新兴的并逐渐取代其他接口标准的数据通信方式,由 Intel、Compaq、Digital、IBM、Microsoft、NEC及Northern .._1671465600

随便推点

091:QuerySet API详解-update和delete_weixin_34378922的博客-程序员宝宝

QuerySetAPI详解-update和delete:update :执行更新操作,在 SQL 底层走的也是 update 命令。比如要将所有 图书的价格提高五元。示例代码如下: Book.objects.update(price=F("price") + 5) # 对比一下上下两种方式 # books = Book.objects.all() ...

Failed with exception java.io.IOException:java.lang.IllegalArgumentException:&nbs_anningzhu的博客-程序员宝宝

hive> show tables;OKFailed with exceptionjava.io.IOException:java.lang.IllegalArgumentException:java.net.URISyntaxException: Relative path in absolute URI:${system:user.name}Time taken: 0.193 se

micropython lvgl_lv_binding_micropython_weixin_39778218的博客-程序员宝宝

Bindings for LittelvGLSee also Micropython + LittlevGL blog post.For advanced features, see Pure Micropython Display Driver blog post.MicropythonMicropython Binding for lvgl (LittlelvGL) provides an a...

MySQL锁机制的原理(2)_mumu_wangwei的博客-程序员宝宝

关于死锁上文讲过,MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了在InnoDB中发生死锁是可能的。如表20-17所示的就是一个发生死锁的例子。表20-17                   InnoDB存储引擎中的死锁例子...

微信小程序-申领福利老客邀请新客之间的逻辑判断_eternity_w的博客-程序员宝宝

微信小程序小结:第一年工作中,第一个比较主流的项目,之前的项目都是用的react-native框架,去开发移动app,没有接触过,也是不断碰壁,慢慢碰出来的能够简单的用rn的组件,去开发项目,但是主流的项目过去的10个月里没怎么接触。项目:朵梵私享会mgm老客活动项目需求:参与活动的客户们首先是两种情况 1. 会员 2. 非会员其次是是否能够参与本次活动 1. 老客 2. 新客活动必须是会员老客才能参与,老客可以开启邀请函,邀请一名新客去领取活动礼品,老客也可以领取一份属于自己的礼品,活

axure中继器求和_Axure学习笔记:中继器之价格统计_weixin_39778106的博客-程序员宝宝

原标题:Axure学习笔记:中继器之价格统计最近开始捯饬Axure,刚做完一个自认为比较简单的表单,大概完整耗时3天……发现中继器里面还是有很多坑。 主要界面 预期实现功能选中每一行,bak(最后一列)出现当前行汇总价格,totalPrice自动汇总;选中三行后,自动选中chk-all;取消选中行,自动取消选中chk-all,且汇总价出现变化;选中/取消选中(含单击、选中)chk-all,自动...

推荐文章

热门文章

相关标签