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

如何实现类型名跟类型的对应, 我们很容易想到map, 没错, 就是使用map实现的. std::map, 等下, 第二部分该填什么类型, 一个函数指针, 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中. 可以通过宏来实现.

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

One

Two

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

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

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

补充:

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

最后再说点什么:

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

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/231158

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 下午2:55
下一篇 2023年2月13日 下午2:55

相关推荐