当前位置: 首页 > news >正文

MFC动态创建(dynamic creation)实现原理

在用到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,动态类型识别,动态创建,序列化).

http://www.xdnf.cn/news/821971.html

相关文章:

  • 炫酷登录注册界面【超级简单 jQuery+JS+HTML+CSS实现】
  • mysql的如何输入dateadd_mysql中date_add()函数的使用?
  • java jersey使用总结_Java 中使用 Jersey 实现上传文件(附加密和解密)
  • android platform.pk8在那个文件下_o泡果奶软件在哪下载 o泡果奶一份礼物魔性文件下载...
  • 英文翻译_英文翻译修改: 益智玩具 Educational Toys
  • 国内外知名安全厂商防火墙默认登录地址、用户名、密码大全,建议收藏备用!
  • 计算机网络安全技术复习知识点总结
  • 一分钟学一个 Linux 命令 - tar
  • Build Setting 之 Code Signing 详解
  • 【C语言】初学者写基础代码的基本步骤
  • NSString使用stringWithFormat拼接
  • Action类的三种编写方式(七)
  • 《圣女之歌2:撒雷母天使》超强全攻略2
  • conn.execute、rs.open、command.execute方法用法大大不同
  • 原神4.7私服制作教程(含下载)
  • 基于javaweb+mysql的ssm校园社团门户网站管理系统(前台、后台)(java+jsp+ssm+mysql)
  • ggggxc学习笔记----ES6----Babel
  • Ubuntu Hardy(8.04) 版本 源列表
  • php 致命错误提示_PHP中的错误提示
  • 2023年打工人一直在纠结:逃离北上广,还是逃回北上广?
  • php cms建站,phpcms建站系统介绍以及phpcms建站流程
  • 黑客零基础自学路线(超详细),学完即可进去“包吃包住”
  • 关于 创建网络套接字失败 10106
  • 电商平台订单项目分析订单数据分析||电商数据分析项目总结!
  • IT技术网站汇总
  • 利用picasa2简单制作超炫壁画
  • 撕衣服小游戏原理
  • 非诚勿扰24灯全灭php,收二手货小伙上非诚勿扰,24盏灯全灭还遭羞辱,最后才知道是收二手豪车身价上亿...
  • 零基础C入门到深入简出
  • RPMforge(Repoforge)源