一种实现C++反射功能的想法(一)

  Java的反射机制很酷, 只需知道类的名字就能够加载调用. 这个功能很实用, 想象一下, 用户只需指定类的名称, 就可以动态绑定类型, 而且只需通过字符串指定, 字符串的使用可以使得用户的修改只需修改一个配置文件就行, 仅仅修改配置文件, 连重新编译都不需要. 喔噢噢, 这种做法将代码的解耦程度做到了极致, 这种技术也不是什么新技术, spring, struct, hibernate......大多数框架都使用到java的反射机制, 而且是作为核心技术, 如果你还未了解反射的话, 赶紧抓紧时间吧.

  有这么一句话, "机器码生汇编, 汇编生C, C生万物...". 同为重量级的编程语言的C/C++有没有类似的反射机制呢? 很遗憾, C++的语法并没有. 首先, 让我们先整理一下C++ 跟 java的区别:

  我对java不熟悉, 所以我大致是这样理解java 实现反射的机制: jvm 在解释执行.class文件时, 遇到了使用反射的字节码, 于是类加载器加载相应的.class, jvm跳到特定的地方继续执行.如果有错误, 还请大家指正. 而C++不同, C++将源程序直接编译成可执行文件, 一般这个可执行文件是不可改变的. 一旦编译完成后, 想要再修改程序, 就必须重新编译.

  那么C++能不能实现类似java的反射呢? 这是个很有吸引力的问题, 大把大把的人在探索解决方案.

  (一) 从根本上解决就是修改编译器, 当编译器扫描到使用反射的语句时生成特定的机器码, 程序执行时能正确跳跃到相应的位置. 听起来跟java原理很像, 还是有点区别的. 这个方案需要解决两个问题, 一是类的序列化问题, 二是编译器的问题. 这两个都不是简单的问题.

  (二) 或许我们将标准放低一点, 实现伪反射就行. 从编程角度上解决问题, 这是比较现实的做法, 不少人提出了各式各样的解决方案:

  1. 使用map 将类名跟类产生器对应起来, 类扩展通过动态链接库来做, 缺点是扩展时必须重新链接, 不过相对于重新编译已经提高了一个层次.

  2. 使用类似注解的方法, 编译的时候先将注解的地方换成C++语句, 在调用C++编译器编译. 缺点是不能做扩展, 扩展必须重新编译.

  

  我的做法也是对上面两种方法的小修小部而已, 不过我还实现了函数的反射功能, 先上demo

  类类型:

 1 class Sharp {
 2
 3 public:
 4     virtual void say()  =0 ;
 5
 6 };
 7
 8 class Point: public Sharp {
 9
10 public:
11     virtual void say();
12 };
13
14 class Line: public Sharp {
15
16 public:
17     virtual void say();
18 };
19
20 class Init {
21
22 public:
23     void declation(const char* arg);
24 };
25
26 void Point::say() {
27
28     std::cout<<"Point\n"<<std::endl;
29 }
30 REGIST(Point)
31
32 void Line::say() {
33
34     std::cout<<"Line\n"<<std::endl;
35 }
36 REGIST(Line)
37
38 void Init::declation(const char* arg) {
39
40     std::cout<<"demo"<<std::endl;
41     std::cout<<"Argument: "<<arg<<std::endl;
42 }
43 REGIST(Init)

  配置文件

1 <Configure>
2     <Function name="declation" scale="Init">
3         <Argument>1</Argument>
4     </Function>
5
6     <Bean name="Sharp" reference="Line" />
7 </Configure>

  程序

1 int main() {
2
3     BeanFactory::sharedFactory().setContextEnv("context.xml");
4     BeanFactory::sharedFactory().configure("configure.xml");
5
6     Sharp* s = static_cast<Sharp*>(BeanFactory::sharedFactory().getBeanByName("Sharp"));
7     s->say();
8 }

  运行结果:

 

  结果跟预期的一样, 在下一篇中我将介绍我实现的方法

时间: 2024-11-07 10:46:53

一种实现C++反射功能的想法(一)的相关文章

一种带有离线消费功能的储蓄卡

刷卡消费很方便,但是你的隐私暴露地也很彻底,以现金消费为例,无异于你每次拿出7块钱买一碗拉面的时候都要打个电话给银行,告诉银行:我的名字是zhy,于今天(2014年6月2日)下午1点10分在苏州x区y街z号的拉面馆花了7块钱买了一碗拉面.然后银行打电话到这家银行,问:身份证号为1234的zhy是否真的在你们店.....,面店老板回答:是的.然后银行就把这次交易很详细地记录了下来.吃碗面真的没什么,但是要是买私密用品呢,买违禁用品呢?幸运的是,现金消费是不记名的匿名消费,在得到消费品的同时,我们感

Java反射获取class对象的三种方式,反射创建对象的两种方式

Java反射获取class对象的三种方式,反射创建对象的两种方式 1.获取Class对象 在 Java API 中,提供了获取 Class 类对象的三种方法: 第一种,使用 Class.forName 静态方法. 前提:已明确类的全路径名. 第二种,使用 .class 方法. 说明:仅适合在编译前就已经明确要操作的 Class 第三种,使用类对象的 getClass() 方法. 适合有对象示例的情况下 package com.reflection; /** * Created by Liuxd

在c++中实现反射的初步想法

最近在思考如何在c++中实现反射.事情的起因是这样的:我们服务器是用c++开发的,如果需要写一些测试用的GM指令的话,需要编写完GM代码后重新编译并且重启进程,工序繁琐且比较耗时.因此就有了想用脚本(lua或py)来写GM的想法.用脚本来做这事我觉得还挺适合的.首先可以免去编译.重启(通过脚本的reload)的过程.其次测试用的GM没有高性能的需求,并且一般在进行自测的阶段时,代码往往是频繁改动的,刚好适合用灵活的脚本:P 接下来的问题就是,要如何在项目中引入脚本.考虑到使用场景,我觉得这个脚本

几种常用的bootstrap功能。

---恢复内容开始--- 我对于bootstrap定义与一种插件,他可以使我们的网页布局更加的炫酷,更加的整洁和合理.他的优点不多说,缺点一个就够我们头疼的,那就是需要记一些长长的英文名. 我为大家说几种常用的bootstrap的常用功能,希望你们用到的时候,可以来看下. <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> <div class="c

三种扩展 Office 软件功能的开发模型对比 – Office Add-In Model, VBA 和 VSTO

当 Office 用户需要针对文档自定义新功能时,可以求助于 VBA 或者 VSTO 两种方式.Office 2013 富客户端以后,微软为 Office 平台上的开发者提供了一种新模型 --- Office Add-In Model,它允许在 Office 应用程序中创建一片区域,并在这片区域中展现网页与文档的交互.开发者可以将高度定制化的 Web 应用或服务集成在 Office 中,使之在整个 Office 平台上可用. 应用程序实际上并没有安装在运行 Office 的计算机上,而是托管在开

以带头节点的循环链表表示队列,并且只设置一个指针指向队尾元素,实现这样的功能的想法。

用循环链来表示队列,并且只有一个指针.我的想法就是在每个节点添加一个布尔型数据,可以用布尔型数据的true和false来判断此节点是否有数据. 这样生成队列的时候和书上类似. 插入数据的时候,先保存原指针指向的点,然后将此指针向下寻找,直到找到一个节点的布尔是false,而下一个是true时,表示此节点是在队尾,将数据插入,并将次节点的布尔值修改为true.如果找不到这样的节点,说明“上溢”或者是个空的链表.抛出异常. 删除数据的时候,和插入类似,先备份原指针,然后用原指针去不断向下寻找,直到找

两种方法实现托盘功能

1为了实现托盘功能,我们可以使用消息机制来进行实现 我们需要使用到windows的一个API函数:BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA lpdata);其中dwMessage可以取以下值: NIM_ADD 向托盘中加入一个图标 NIM_MODIFY 修改托盘中的图标 NIM_DELETE 从托盘中删除一个图标 参数pnid是NOTIFYICONDATA结构的一个引用.该结构的原型如下: typedef struct _NO

使用另一种方式实现会话功能

有的时候时候并不一定要使用SESSION,或不能使用WEB的SESSION,有的时候考虑自己来定义会话操作.可以用自己的代码来会话的操作.我也读了System.Web.SessionState的InProcess实现代码,如果按它的原理来的话.将会有很大的工作量. 那好吧,我们还有两个可选的方案,一个是 System.Web.Cache , 一个是 System.Runtime.Cache , MSDN也说了两个功能相似,Runtime的出现是为了可以脱离对于System.Web的依赖. 写个控

使用Java的反射功能调用类中的方法

最近一直在搞Java的反射,今天使用反射调用方法时出现了很多问题,主要是没有详细参考官方API.所以走了很多弯路. 所以想把这个例子记下来,供自己也供他人学习. package com.mine.practice.reflect; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 使用反射调用类中的方法 * @author 2014-11-5 上午10:51:28