C++反射的一种实现方法详解

一、注册辅助类

ClassRegistry:模板函数,用于data、module、contextdata的注册,其中的函数解析:

create_object:从RegistryMap里找到传入name对应的RegistryNode(RegistryNode保存了名字和构造函数),调用构造函数返回。

register_class:用传入的name和constructor注册RegistryMap,只在Register的构造函数里面调用,后面会在ClassRegister<IData> DataRegister、ClassRegister<IModule> ModuleRegister、ClassRegister<IContextData> ContextDataRegister用到。RegistryMap里面的数据是从register_class这个方法插入数据进去的,后面会在IMPLEMENT_XXX中调用到这个。

fill_name_array:找到RegistryMap里面注册的name,插入传入参数。

二、使用到的宏定义

2.1 data

REGISTER_DATA:声明构造data_class的函数 __construct_##name##_data() ,其中调用了data_calss的构造函数;
声明获取class的get_##name,函数体的get_data从 sign_data_map里面获取到对应的IData

#define REGISTER_DATA(data_class, name)          \
 inline ::wmf::IData* __construct_##name##_data() { return new data_class; } \
 namespace wmf {                \
 namespace internal {              \
 inline data_class* get_##name() { return get_data<data_class>(#name); }  \
 }                   \
 } // wmf::internal

IMPLEMENT_DATA:调用DataRegister的构造函数。声明变量__##name##_module_register,这里会将输入的name和构造函数__construct_##name##_data注册到RegistryMap中;

#define IMPLEMENT_DATA(name)        \
 ::wmf::internal::DataRegister __##name##_module_register( \
  #name, __construct_##name##_data)

使用:

在需要用到的.cpp文件的的.h文件的位置调用REGISTER_DATA,声明构造函数和获取data的get_xxx函数。

在每个service的cpp文件视线中调用IMPLEMENT_DATA,注入RegistryMap。

在每个service的cpp文件的InitInjection中,INJECT_DATA_MODULE_DEPENDENCY把这个词典注入到module中。

2.2 module

REGISTER_MODULE:声明__construct_#name##_module(),返回new module_class;

声明获取class的get_##name,函数体里面返回ModuleMap中保存的对象(cast_module从ModuleMap里面找到其对应的对象,如果找不到,则从RegisterMap里面找到其构造函数,并调用create_object之后插入ModuleMap,并返回新建的对象(RegisterMap里面的数据从IMPLEMENT_XXX来的))

#define REGISTER_MODULE(module_class, name)    \
 inline ::wmf::IModule* __construct_##name##_module() { \
 return new module_class;        \
 }              \
 namespace wmf {          \
 namespace internal {         \
 inline module_class* get_##name(::wmf::Context& ctx) { \
 return ctx.cast_module<module_class>(#name);   \
 }              \
 }              \
 } // wmf::internal

IMPLEMENT_MODULE:声明__##name##_module_register变量,以插入RegistryMap。

#define IMPLEMENT_MODULE(name)        \
 ::wmf::internal::ModuleRegister __##name##_module_register( \
  #name, __construct_##name##_module)

使用:

在新增module的.h文件最后调用REGISTER_MODULE声明了在IMPLEMENT_MODULE中会用到的构造函数,以及声明了从ModuleMap中获取其对象的get_xxx函数。

在service的最后调用IMPLEMENT_MODULE,把module注册到RegistryMap中。

2.3 context data

REGISTER_CONTEXT_DATA:声明__construct_##name##_context_data(),新建data_class;

声明获取class的get_##name,函数体里面通过name查找到ContextDataMap保存的名字签名对应的IContextData,转换为data_class返回。

#define REGISTER_CONTEXT_DATA(data_class, name)           \
 inline ::wmf::IContextData* __construct_##name##_context_data() { \
  return new data_class;                     \
 }                                 \
 namespace wmf {                          \
 namespace internal {                       \
 inline data_class* get_##name(const ::wmf::Context& ctx) {    \
  return ctx.cast_context_data<data_class>(#name);        \
 }                                 \
 }                                 \
 } // wmf::internal

IMPLEMENT_CONTEXT_DATA:声明__##name##_context_data变量,这里会将输入的name和构造函数__construct_##name##_context_data注册到RegistryMap中;

#define IMPLEMENT_CONTEXT_DATA(name)              \
 ::wmf::internal::ContextDataRegister __##name##_context_data( \
   #name, __construct_##name##_context_data)

2.4 index_data

DECLARE_INDEX_DATA:N for name, VT for VersionIndex 类型。声明类型C为用类型VT组装,path、name、desc用N组装的VIAdaptor类型。

#define DECLARE_INDEX_DATA(VT, C, N)                    \
 extern const char __index_##N##_path[];                  \
 extern const char __index_##N##_name[];                  \
 extern const char __index_##N##_desc[];                  \
 typedef wmf::VIAdaptor<argument_type<void(VT)>::type, __index_##N##_path, \
             __index_##N##_name, __index_##N##_desc>      \
   C

DEFINE_INDEX_DATA:N for name,这里是声明一堆string变量,用于data的path、name、desc。

#define DEFINE_INDEX_DATA(N)            \
 const char __index_##N##_path[] = #N "_path";   \
 const char __index_##N##_name[] = #N "_name";   \
 const char __index_##N##_desc[] = #N "_desc";   \
 DEFINE_string(N##_path, "", "index " #N " path"); \
 DEFINE_string(N##_name, "", "index " #N " name"); \
 DEFINE_string(N##_desc, "index_" #N, "index " #N " desc")

2.5 injection

DEFINE_INJECTION:定义一个把object_ref变量设置为class_type*类型的传入变量的函数。

#define DEFINE_INJECTION(injection_name, class_type, object_ref) \
 void set_##injection_name(class_type* module) { object_ref = module; }

INJECT_OBJECT_OBJECT_DEPENDENCY:调用object_to这个对象的set_##injection_name方法,传入参数是object_from的引用。结合DEFINE_INJECTION就是把object_from设置到object_to这个对象里面。

#define INJECT_OBJECT_OBJECT_DEPENDENCY(injection_name, object_from, \
                    object_to)          \
 (object_to).set_##injection_name(&(object_from))

INJECT_MODULE_DEPENDENCY:在上下文context中找到module_from的变量,注入到同一个上下文的module_from里面。

#define INJECT_MODULE_DEPENDENCY(injection_point, context, module_from, \
                 module_to)               \
 ::wmf::internal::get_##module_to(context)->set_##injection_point(   \
   ::wmf::internal::get_##module_from(context));

INJECT_DATA_MODULE_DEPENDENCY:把data注入到通过上下文context获取的module_to中。

#define INJECT_DATA_MODULE_DEPENDENCY(injection_point, context, data, \
                   module_to)           \
 ::wmf::internal::get_##module_to(context)->set_##injection_point(  \
   ::wmf::internal::get_##data());

INJECT_MODULE_OBJECT_DEPENDENCY:通过上下文context获取的module_from注入到object_to中。

#define INJECT_MODULE_OBJECT_DEPENDENCY(injection_point, context, module_from, \
                    object_to)               \
 (object_to).set_##injection_point(                      \
   ::wmf::internal::get_##module_from(context));

INJECT_OBJECT_MODULE_DEPENDENCY :object_from注入到通过上下文获取的module_to中。

#define INJECT_OBJECT_MODULE_DEPENDENCY(injection_point, context, object_from, \
                    module_to)               \
 ::wmf::internal::get_##module_to(context)->set_##injection_point(      \
   &(object_from))

使用:

在上下文相关的session中调用INJECT_MODULE_DEPENDENCY、INJECT_DATA_MODULE_DEPENDENCY;

INJECT_MODULE_DEPENDENCY用于把session相关的信息(比如session_docs、request、response)注入到module中,module的意思是这个请求需要过的模块名。

INJECT_DATA_MODULE_DEPENDENCY用于把data注入到module中。

三、总结

3.1 新增一个module

在新增module的.h文件最后调用REGISTER_MODULE声明了在IMPLEMENT_MODULE中会用到的构造函数,以及声明了从ModuleMap中获取其对象的get_xxx函数。

在service的最后调用IMPLEMENT_MODULE,把module注册到RegistryMap中。

在上下文相关的session中调用INJECT_MODULE_DEPENDENCY、INJECT_DATA_MODULE_DEPENDENCY;

INJECT_MODULE_DEPENDENCY用于把session相关的信息(比如session_docs、request、response)注入到module中,module的意思是这个请求需要过的模块名。

INJECT_DATA_MODULE_DEPENDENCY用于把data注入到module中。

3.2 代码回顾

ClassRegistry用于给第二项的一堆宏使用。module于类的映射关键在于RegistryMap,新增一个module的时候,服务会去RegistryMap里面找名字对应的构造函数。RegistryMap里面的数据是在IMPLEMENT_MODULE的时候注入进来的name和类的对应关系。配置文件里面配的是module的链条,比如需要过AModule,BModule,这时候就在init的时候把所有module都插进去,然后在schedule_impl里面调用每个module的run函数。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • C++ 反射机制详解及实例代码

    C++ 反射机制 一.前言: Java有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载.探知.使用编译期间完全未知的classes.换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体.或对其fields设值.或唤起其methods.然而C++是不支持反射机制,虽然C++有RTTI(运行时类型识别).但是想要实现C++对象序列化,序列化就是存储到磁盘上,将对象变成一定格式的二

  • 在C++中反射调用.NET的方法(一)

    为什么要在C++中调用.NET 一般情况下,我们常常会在.NET程序中调用C/C++的程序,使用P/Invoke方式进行调用,在编写代码代码的时候,首先要导入DLL文件,然后在根据C/C++的头文件编写特殊的C#平台调用代码,例如像下面这个样子: [DllImport("Interop.dll",EntryPoint = "Multiply",CharSet = CharSet.Ansi)] static extern int Multiply(int factor

  • 在C++中反射调用.NET的方法(二)

    反射调用返回复杂对象的.NET方法 定义数据接口 上一篇在C++中反射调用.NET(一)中,我们简单的介绍了如何使用C++/CLI并且初步使用了反射调用.NET程序集的简单方法,今天我们看看如何在C++与.NET程序集之间传递复杂对象. 先看看.NET程序集的一个返回对象的方法: public IUserInfo GetUserByID(int userId) { IUserInfo userinfo= EntityBuilder.CreateEntity<IUserInfo>(); user

  • 在C++中反射调用.NET的方法(三)

    在.NET与C++之间传输集合数据 上一篇<在C++中反射调用.NET(二)>中,我们尝试了反射调用一个返回DTO对象的.NET方法,今天来看看如何在.NET与C++之间传输集合数据. 使用非泛型集合的委托方法 先看看.NET类中的一个返回列表数据的方法: //返回List或者数组,不影响 C++调用 public List<IUserInfo> GetUsers(string likeName) { List<IUserInfo> users = new List&l

  • C++反射的一种实现方法详解

    一.注册辅助类 ClassRegistry:模板函数,用于data.module.contextdata的注册,其中的函数解析: create_object:从RegistryMap里找到传入name对应的RegistryNode(RegistryNode保存了名字和构造函数),调用构造函数返回. register_class:用传入的name和constructor注册RegistryMap,只在Register的构造函数里面调用,后面会在ClassRegister<IData> DataR

  • JSP 获取用户的真实IP两种实现方法详解

    JSP 获取用户的真实IP两种实现方法详解 在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了 Apache,Nagix等反向代理软件就不能获取到客户端的真实IP地址了.如果使用了反向代理软件,用 request.getRemoteAddr()方法获取的IP地址是:127.0.0.1或 192.168.1.110,而并不是客户端的真实IP. 经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿

  • Java线程三种命名方法详解

    这篇文章主要介绍了Java线程三种命名方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.实例化一个线程对象 Thread t = new Thread(); t.setName("甲"); 2.实例化一个线程对象的同时,通过构造方法对线程进行命名 Thread(Runnable r, String name) Thread t = new Thread(() -> {}, "甲"); 3.使用自定义

  • Android 滑动小圆点ViewPager的两种设置方法详解流程

    第一种方法: 一.测试如下,直接设置小圆点不是图标 二.准备工作 1.在drawable创建dot.xml,设置小圆点,比较方便 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="t

  • Vue屏幕自适应三种实现方法详解

    目录 使用 scale-box 组件 设置设备像素比例(设备像素比) 通过JS设置zoom属性调整缩放比例 使用 scale-box 组件 属性: width宽度 默认1920 height高度 默认1080 bgc背景颜色 默认"transparent" delay自适应缩放防抖延迟时间(ms) 默认100 vue2版本:vue2大屏适配缩放组件(vue2-scale-box - npm) npm install vue2-scale-box 或者 yarn add vue2-sca

  • java中关于Map的三种遍历方法详解

    map的三种遍历方法!集合的一个很重要的操作---遍历,学习了三种遍历方法,三种方法各有优缺点~~ 复制代码 代码如下: /* * To change this template, choose Tools | Templates * and open the template in the editor. */package cn.tsp2c.liubao;import java.util.Collection;import java.util.HashMap;import java.util

  • Java SHA-256加密的两种实现方法详解

    本文实例讲述了Java SHA-256加密的两种实现方法.分享给大家供大家参考,具体如下: 最近在做注册的一个功能,密码要进行加密,一开始想用MD5加密,但是听说被破解了已经,于是想玩玩SHA-256加密.学习了下,总结两种方法供后面参考: 1.利用Apache的工具类实现加密: maven: <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifac

  • JS小球抛物线轨迹运动的两种实现方法详解

    本文实例讲述了JS小球抛物线轨迹运动的两种实现方法.分享给大家供大家参考,具体如下: js实现小球抛物轨迹运动的大致思路: 1.用setInterval()方法,进行间隔性刷新,更新小球位置,以实现动态效果 2.绘制小球和运动区域,运动区域可通过flex布局实现垂直居中 3.用物理公式S(y)=1/2*g*t*t,S(x)=V(x)t来计算路径 现确定V(x)=4m/s,刷新的时间间隔设置为0.1s.原本px和米之间的转换,不同尺寸转换不同,本例采用17寸显示器,大约1px=0.4mm.但浏览器

  • PHP跳转页面的几种实现方法详解

    •PHP页面跳转一.header()函数header()函数是PHP中进行页面跳转的一种十分简单的方法.header()函数的主要功能是将HTTP协议标头(header)输出到浏览器.header()函数的定义如下:void header (string string [,bool replace [,int http_response_code]])可选参数replace指明是替换前一条类似标头还是添加一条相同类型的标头,默认为替换.第二个可选参数http_response_code强制将HT

  • JavaScript函数的4种调用方法详解

    在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C#或其他描述性语言那样仅仅作为一个模块来使用.函数有四种调用模式,分别是:函数调用形式.方法调用形式.构造器形式.以及apply形式.这里所有的调用模式中,最主要的区别在于关键字 this 的意义,下面分别介绍这个几种调用形式. 本文主要内容: 1.分析函数的四种调用形式2.弄清楚函数中this的意义3.明确构造函对象的过程4.学会使用上下文调用函数 一.函数调用形式 函数调用形式是最常见的形式,也是最

随机推荐