技术标签: # 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的基础上再扩充一些功能.
首先CRuntimeClass定义中除了RTTI信息,添加
struct CRuntimeClass{
CObject* ( *m_pfnCreateObject)(); //函数指针,指向的函数中会通过new实例化一个对象
CObject* CreateObject()
//其他信息省略掉了
}
其中函数CreateObject定义如下
CObject* CRuntimeClass::CreateObject(){
CObject* pObect = NULL;
pObject =(*m_pfnCreateObject)();
}
假如定义一个继承自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();
///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(......)//为讨论方便这里省略掉了
有了上面两个宏,然后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,动态类型识别,动态创建,序列化).
报错: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文件中引用类报错,网上找了一圈也没有找到方法。解决方法:原来就是因为不
最近项目要实现一个需求这种效果,黄色背景有圆角,字体内容会变化,首先想到的是用ImageSpan之类的来实现,可是找了好多没找到,无意之间想到可以自己写个自定义View来实现呀。于是思路就是黄色背景的是一个TextView A可以自己画圆角,第一行的“考上北京大学的经验!考上北京”一个TextView B,“大学的经验”一个TextView C即可实现。String textString = "考...
前段时间在学习robot framework + selenium + ride自动化测试框架,今天腾出一些时间总结一下学习该框架的第一步-框架的搭建,对该框架的使用总结持续进行。因为我使用的是Mac,所以以下搭建过程以Mac的搭建为例。首先,安装python3.7,安装成功后,配置环境变量: open ~/.bash_profile PATH=“/Library...
2019独角兽企业重金招聘Python工程师标准>>> ...
文章目录说明报错日志内容查看secure日志查看【知道就行】messages日志查看【这里面有记录】处理方法key文件删除修改配置文件中的UsePAM上面步骤过程测试自己可以ssh自己了工具也可以正常连接了别的服务器ssh自己【必看】说明我的一台虚拟机IP是:192.168.59.133出问题了,任何服务器使用任何用户ssh均报错,甚至连自己都不能ssh自己。也不能使用任何工具连接上该服务器,报错如下ssh报错如下任何服务器ssh报错内容均一样:报错内容均为:Permission d
SCSI与USB的关系由于BusHound在使用过程中,直接把USB和SCSI混为一谈,相关设计的时候这些东西也经常放在一起来讲,导致稍微缺乏经验的人傻傻分不清楚。因此在这里特别说明一下SCSI和USB分别是什么东西,以及他们是怎么联系在一起的。一、USB概述简介通用串行总线 (Universal Serial Bus,USB) 是一种新兴的并逐渐取代其他接口标准的数据通信方式,由 Intel、Compaq、Digital、IBM、Microsoft、NEC及Northern .._1671465600
QuerySetAPI详解-update和delete:update :执行更新操作,在 SQL 底层走的也是 update 命令。比如要将所有 图书的价格提高五元。示例代码如下: Book.objects.update(price=F("price") + 5) # 对比一下上下两种方式 # books = Book.objects.all() ...
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
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...
关于死锁上文讲过,MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了在InnoDB中发生死锁是可能的。如表20-17所示的就是一个发生死锁的例子。表20-17 InnoDB存储引擎中的死锁例子...
微信小程序小结:第一年工作中,第一个比较主流的项目,之前的项目都是用的react-native框架,去开发移动app,没有接触过,也是不断碰壁,慢慢碰出来的能够简单的用rn的组件,去开发项目,但是主流的项目过去的10个月里没怎么接触。项目:朵梵私享会mgm老客活动项目需求:参与活动的客户们首先是两种情况 1. 会员 2. 非会员其次是是否能够参与本次活动 1. 老客 2. 新客活动必须是会员老客才能参与,老客可以开启邀请函,邀请一名新客去领取活动礼品,老客也可以领取一份属于自己的礼品,活
原标题:Axure学习笔记:中继器之价格统计最近开始捯饬Axure,刚做完一个自认为比较简单的表单,大概完整耗时3天……发现中继器里面还是有很多坑。 主要界面 预期实现功能选中每一行,bak(最后一列)出现当前行汇总价格,totalPrice自动汇总;选中三行后,自动选中chk-all;取消选中行,自动取消选中chk-all,且汇总价出现变化;选中/取消选中(含单击、选中)chk-all,自动...