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

  如何实现类型名跟类型的对应, 我们很容易想到map, 没错, 就是使用map实现的. std::map<std::string, .....>, 等下, 第二部分该填什么类型, 一个函数指针, auto create()? auto只是占位符, 编译器好像不会让你通过吧. 我们需要一种容器, 可以存放所有的类型,  模板. 

  由于声明这个容器是并不能包含模板参数, 这里借鉴了boost 库中any的代码, 原理如下:

 1 class Container {
 2 
 3 private:
 4 
 5     class bridge {
 6 
 7     public:
 8         bridge(){}
 9         virtual ~bridge(){}
10         virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) = 0;
11         virtual void* instanceOfClass() = 0;
12     };
13 
14     template<typename ValueType>
15     class holder: public bridge {
16 
17     public:
18         virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) override{};
19         virtual void* instanceOfClass() override{};
20     };
21 
22     template<typename ValueType>
23     class holder<ValueType*>: public bridge {
24 
25     public:
26         holder(ValueType* item){}
27         virtual ~holder() {}
28 
29         virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) override{
30 
31         }
32         
33         virtual void* instanceOfClass() override{
34 
35         
36
37 } 38 }; 39 40 bridge* content_; 41 public: 42 Container(){} 43 ~Container(){ 44 Alloc::dellocate(content_); 45 } 46 47 template<typename ValueType> 48 Container(ValueType* item) { 49 50 holder<ValueType*>* h = static_cast<holder<ValueType*>*>(Alloc::allocate(sizeof(holder<ValueType*>))); 51 new(h) holder<ValueType*>(item); 52 content_ = h; 53 } 54 55 // three arguments most, and type are char* 56 void invoke(unsigned long long addr, const std::vector<const char*>& args) { 57 58 content_->invoke(addr, args); 59 } 60 61 void* instanceOfClass() { 62 63 return content_->instanceOfClass(); 64 } 65 66 };

  Container只是一层包装, 隐藏了模板参数, 真正存储类型的是继承bridge的holder子类, bridge提供接口, 由于纯虚函数不能是模板函数, 所以返回实例是必须强制转型为void* 指针, 由客户端再强制转型回来.如何存储一个类类型的信息呢, 最简单, 保存该类型的一个指针变量就行. 其他的交由编译器的模板处理. 然后将类注册, 即插入map中. 可以通过宏来实现.

  好了, 到了最后一步, 函数类型问题. 我们的目标是在配置文件中声明类似的语句:

  <Function name="declation", scale = "Init">

    <Argument>One</Argument>

    <Argument>Two</Argument>

  </Function>

  只要这样声明就能生产 void declation(const Init*, One, Two)这样的函数声明. 

  由于文本中只能保存基本的类型, 你不可能用在文本中指定某个参数是指针吧. 还有是函数个数的问题, 我本以为模板的可变参数能起点作用, 结果发现并不是我想要的. 好吧, 所以只能再做一个限制条件, 3个参数最多, 如果你写的函数参数多余三个, 我想你肯定有办法减少参数个数的, 还有参数类型都是字符串, 从字符串到其他基本类型的转换必须由函数自己解决. 这样, 解决思路很清晰了, 首先根据scale类型获取容器, 根据函数名获取地址, 根据参数个数获取函数类型, 最后执行.

  所有的源代码我都上传在github上面, reflect

 

  补充:

  之前我一直以为该实现反射的方式只能在debug下才有效, 应为debug下编译器会玩可执行文件中加入大量的调试信息, 当使用release版本时, 并没有这些编译信息, 或许可以使用之前保存过的信息, 但可能会对内存地址有所影响. 之后我详细了解了elf文件格式后, 发现并不会影响, 至少我目前的测试是没有影响的. debug时是将调试信息以dwarf格式的段添加到可执行文件后, 而并不是随机穿插在程序中, 所以只有release时代码并没有修改, 注意宏的修改, 就可以使用debug时保存下来的调试信息.当我发现这个时有点小兴奋, 他解除了一个限制条件, 使得这种想法或许可以有更大的实用之处.

  

  最后再说点什么:

  这是自己第一次写博客, 自从上了大学以后, 没学过语文, 以前并不知道语文是这么重要, 直达现在发现自己并不能将自己想要说的流畅地, 有层次地表达出来, 写下来. 这几篇博客修修补补还是花了自己一点时间. 如果你在看完之后, 笑道这都写了写什么东西啊, 我也并不会介意的. 以前是懒与去经营自己的博客, 当发现自己写出属于自己的博客时, 还是挺有满足感的, 我也会继续写下去, 继续锻炼, 或许多年以后翻翻自己写过的东西, 回信一下自己当时的所思所想, 也将是已将很有趣的事情吧.

你可能感兴趣的:(一种实现C++反射功能的想法(三))