zoukankan      html  css  js  c++  java
  • 一种实现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
    "<<std::endl;
    29 }
    30 REGIST(Point)
    31 
    32 void Line::say() {
    33 
    34     std::cout<<"Line
    "<<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 }
    复制代码

      运行结果:

     

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

    http://www.cnblogs.com/YouJie/p/5328554.html

  • 相关阅读:
    结对-贪吃蛇游戏-需求分析
    结对-贪吃蛇游戏-结对项目总结
    团队-团队编程项目作业名称-成员简介及分工
    《结对-结对编项目作业名称-需求分析》猜拳游戏安卓
    《20170830-构建之法:现代软件工程-阅读笔记》本周阅读了第四章的第四节
    对软件工程的期望
    自我介绍
    GIT基本使用方法
    结对-简易计算器-设计文档
    结对-简易计算器-开发环境搭建过程
  • 原文地址:https://www.cnblogs.com/findumars/p/5512500.html
Copyright © 2011-2022 走看看