偷Microsoft师学MFC艺:且看C++如何支持反射

如果你问一个IT人士“C++如何实现类似Java的反射?”,结果会怎样呢?~!@#¥%……&*,估计大部分人都会要稍微思考了一下,或者直接说“C++根本就不支持反射的呀!”。

是的,C++语言本身是不支持反射的,但实际应用中总是会有将对象序列化的需求,总不可能C++不支持,我们就不用C++了,既然发明C++的大师们没有考虑这个,那我们只有自己动手了,毛主席说过“自己动手,丰衣足食”!

天生限制

C++语言本身不支持反射机制,但C++对象总是要序列化的,序列化就是存储到磁盘上,将对象变成一定格式的二进制编码,然后要用的时候再将保存在磁盘上的二进制编码转化成一个内存中的对象,这个过程中总是需要有一个指示来告诉编译器要生成什么样的对象,最简单的方式当然就是类名了,例如:将一个ClassXXX对象存储到磁盘上,再从磁盘读取的时候让编译器根据“ClassXXX”名称来new一个对象。

但是问题出现了,C++语言本身不支持反射,也就是说不能通过如下方式生成一个对象:

ClassXXX object = new “ClassXXX”;

 

工厂方法

当然,这样的方法不行,那我们只有另辟蹊径。最简单的就是工厂方法了:

ClassXXX* object = FactoryCreate(“ClassXXX”);

至于FactoryCreate的设计就很简单了,if的集合就可以了:

if(name = “ClassXXX”)

return new ClassXXX;

if(name = “ClassYYY”)

return new ClassYYY;

 

看起来不错,来个类名就可以生成对应的对象,功能上解决了根据类名生成对象的问题。

假如以上所有的代码都有你一个人编写,那当然问题不大,但是假如有一天你的公司扩大了,这部分代码由两个不同的组A和B来维护,啊哈,问题来了,A组每添加或者修改一个类,都要通知B组更新FactoryCreate函数,也就是说A组的任何关于类的修改,都需要B组来修改,但实际上B的修改不产生任何价值,而且不胜其烦,永无止尽!!如果哪天来了一个新员工,由于对这个规定还不清楚,忘记了通知,那就完了:编译通不过!

一个公司内都会产生如此多的问题,更何况微软这样的大公司是面对全球的各种各样的客户,如果微软把这部分做进框架代码中,呵呵,那微软所有的人不用干其他事情了,每天处理来自全球的要求修改FactoryCreate函数的邮件和电话就够他们忙的了:)

 

回调工厂

既然此路不好走,那么我们再考虑其它方法吧,一个可选的方法是将FactoryCreate做成回调函数,框架提供注册接口RegisterFactoryCreate,框架函数如此实现:

typedef CObject* (*FactoryCreate_PTR)(String name);

RegisterFactoryCreate(FactoryCreate_PTR fc_ptr);

应用代码如此实现:

CObject* MyFactoryCreate(String name);

RegisterFactoryCreate(MyFactoryCreate);

到这里一个框架和应用分离的反射机制基本实现了,你是否长吁一口气,然后准备泡杯咖啡,稍微放松一下呢?确实可以稍微休息一下了,毕竟我们完成了一件非常了不起的事情,让C++实现了反射。

 

但你只悠闲了一两天,麻烦事就来了。员工张三跑来向你抱怨“老大,李四注册的反射函数把我的覆盖了”!哦,你仔细一看,My god,这个注册函数只能注册一个反射函数,后注册的就把前面的覆盖了!

怎么办?总不可能又要求所有的类的反射函数都在一个工厂里实现吧,那这样就又回到了工厂方法中描述的时代了。

当然,聪明的你估计很快就能想出问题的解决方法,将RegisterFactoryCreate函数稍加修改就能满足要求了,新的实现如下:

RegisterFactoryCreateFactoryCreate_PTR fc_ptr,String className)

然后要求每个类都单独写自己的FactoryCreate_PTR函数,类似如下方式:

static CObject* ClassXXX::CreateClassXXX (){

       return new ClassXXX;

};

 

static CObject* ClassYYY::CreateClassYYY(){

       return new ClassYYY;

};

 

到此为此终于大功告成,通过我们的智慧实现了C++的反射功能!一股自豪感油然升起:)

 

最后的杀手锏:宏

当你为自己的聪明才智而骄傲的时候,那边却有几个开发的兄弟在发出抱怨“唉,这么多相似的函数,看着都眼花,每个类都要写,烦死了”。

或者有一天,你要在每个类的CreateClass函数中增加一个其它功能(例如日志),那么开发的兄弟真的是要烦“死了”!!!

 

其实仔细一看,包括函数申明、函数定义、函数注册,每个类的代码除了类名外其它都是一模一样的,有没有简单的方法呢?

肯定是有的,这个方法就是宏了,按照如下方法定义宏:

#define DECLARE_CLASS_CREATE(class_name) /

static CObject* CreateClass## class_name ();

 

#define IMPL_CLASS_CREATE(class_name) /

static CObject* CreateClass## class_name (){  /

       return new class_name;             /

};

 

#define REG_CLASS_CREATE(class_name) /

RegisterFactoryCreate(class_name::CreateClass## class_name, #class_name);

注:##是连接符,将两个字符串连接起来,#是将class_name作为字符串处理。

 

大家可以比较一下,用了宏和不用宏是不是代码感觉完全不一样呢?而且那天需要增加一个简单的功能,只需要改宏定义就ok了,不要全文搜索所有相关函数,然后一个一个的重复添加。

 

到这里才真正是大功告成!!

 

后记

某天分析Spring的IOC时,看到Digester最后利用的实际上是Java的反射机制来根据XML文件定义生成Java对象,突发奇想:如果是C++该怎么办?

于是自己就开始分析起来,分析了一段时间突然想起微软的MFC不正是要支持C++对象序列化的吗?

赶紧打开深入浅出MFC,重新将这部分研究了一下。看到微软的天才们在MFC中用宏来实现RTTI、Dynamic Create、Seralize功能时,我反过来思考“如果是我,我会如何设计?”、“为什么会这么设计”?然后一一分析这些各种可能的实现方式,一步一步的推导,最后发现竟然自然而然的就推出了MFC的这种实现方式!

当然,MFC的实现代码和我给出的代码不一样(注册方式不一样),但设计思想是一样的,各位看官可以自行稍加分析就明白了。

MFC的详细实现可以参考侯捷的《深入浅出MFC》。

 

时间: 2024-07-31 04:38:51

偷Microsoft师学MFC艺:且看C++如何支持反射的相关文章

c++-我现在该学什么?window程序设计啃到第九章,想学MFC但是已经过时了,C++的路下面该怎么走

问题描述 我现在该学什么?window程序设计啃到第九章,想学MFC但是已经过时了,C++的路下面该怎么走 我是自修计算机,连本科文凭都是家里蹲自考的,主修C++,现在不知道该学什么了,<window程序设计>只啃到第九章,啃不下去了,太多的API函数,在啃下去也是浪费时间,最多就是熟悉些API的运用....然后啃<深入浅出MFC>今天啃到第三篇有卡住了,也不想在MFC上浪费太多时间.....我下面该学什么.....完全没有方向呀,C++的路下面该怎么走...... 解决方案 AP

web.xml-刚开始学java,现在看一个项目看不懂到底用什么框架

问题描述 刚开始学java,现在看一个项目看不懂到底用什么框架 看起来是spring,但是又觉得有点不同,请帮我看一下,下面是web.xml文件内容和springContext <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.s

艺网网络为您提供50M支持ASP+PHP的免费空间_免费FTP空间

艺网网络为您提供50M支持ASP+PHP的免费空间 以下是他们论坛上的介绍内容: 艺网网络为赞助本论坛,回报大家的厚爱,现决定开放50M免费PHP+ASP+FTP全能空间.空间介绍: 1.完全免费型,免费时间:永久.但如果一个月没有管理,将会被删除,删除后不可恢复. 2.空间支持ASP,FTP,FSO,JMAIL,,access,水印文字,无组件上传等,支持小型论坛. 3.空间使用带宽100M独享,电信线路,限制IIS. 4.空间FTP地址是您的域名或222.189.228.89端口:21,请勿

2345看图王支持什么图片格式?

2345看图王支持什么图片格式?   2345看图王 2345看图王支持格式有哪些 2345看图王比传统图片查看器支持更多的图片格式,除了BMP/PNG/JPG等常见图像格式,更兼容PSD/RAW等专业图像格式,所支持的格式多达69种; 2345看图王适用于所有Windows下系统,包括微软最新推出的Win8; 2345看图王兼容了包括WinXP,Win7,ACDSEE在内的主流图片查看器的大部分快捷键,即使初次上手的用户也能很快操作自如.

怎么看电脑主板是否支持DDR4内存?

Q:DDR4内存用什么主板? A:并不是所有的主板都支持DDR4内存,由于DDR4属于新一代内存,对主板和CPU都有要求,目前只有一些新CPU和主板支持DDR4内存. 关于DDR4内存用什么主板,这个主要需要根据CPU与主板的选择,加以考虑.就目前而言,仅Intel平台的X99主板.最新的100系列(B150.Z170等)主板支持DDR4内存. 而AMD平台,暂时还没有任何一款CPU与主板支持DDR4内存.不过,今年AMD平台将推出基于新AM4接口的处理器,届时AMD新CPU会支持DDR4内存,

五封信——大专生的自卑、工作不好想考研、大一就着急的孩子、是否学MFC

[来信]老师,我只是一名大专生.找工作很自卑 我是2012级专科生,在学校里认真学习.说起我如何考到大专,其实今年中专应届生,通过自主招生考到了这边比较好的3a吧(这也是中专生能考到的最好的学校了,这个学校不通过普通高考招中专生). 在中专学校里,学校教的东西太容易,我只是应付了一下.在家里我第一年学了c语言,学完之后自学了数据结构和算法,能够实现编码吧,后来做了一些基础的acm.那时的我很刻苦,整天想算法有10小时吧.只想把不会的题马上做出来,一年的算法学习使我的算法水平比一般学生要强.后来我

怎么看显示器是否支持壁挂

  一.如何判断显示器是否支持壁挂? 并不是所有的显示器都支持壁挂功能,有些显示器为了外观时尚漂亮,已经不再使用平坦的背面设计.这样一来并不符合标准VESA壁挂规格,就无法实现壁挂功能. 平面+螺丝孔是判断壁挂支持重要因素 要看自家的显示器是否支持壁挂功能,大家可以通过观察液晶显示器的背面是否有四个呈矩形排列的螺丝孔,这个是安装壁挂用的.如果有,才能确定支持壁挂功能,如果没在,则不支持壁挂功能,不支持壁挂. 二.液晶显示器如何壁挂? 显示器壁挂其实并不难,两个步骤即可完成. 1.首先需要拆卸显示

关于“IT学子成长指导”专栏及文章目录

迂者专栏关键词 就 业 大一 大二 大三 大四 自学 职 场 专业+兴趣 研究生 硕士 规 划 考 研 大学生活 迷 茫 计算机+专业 基本功 学习方法 编程 基 础 实践 读书 前 途 成 长 社团 课程 IT行业 奋 斗 CSDN社区对我的专访.再访(一).再访(二).我的大学.Follow my heart,将为IT菜鸟起飞建跑道的事业进行下去. 本博义务咨询纯利用业余时间,本职工作需要优先,故不能保证所有来信在当天能得到回复,有的问题还需要给我留出思考时间.来信只需一封,请不要用一信多发

使用Microsoft.NET Frameworks创建Windows应用程序

window|程序|创建 使用 Microsoft.NET Frameworks 创建基于 Windows 的应用程序 Shawn Burke Microsoft Corporation 2000年9月 摘要: :本文介绍了 Win 表单这一新的窗体程序包,借助这一程序包,开发人员能够充分利用 Microsoft Windows 操作系统所提供的 UI 功能. 目录 简介 介绍 Win Forms 更好的易学易用性 布局 GDI+ 访问底层系统 结论 ----------------------