使用过C#或者Java 的童鞋,应该对这些语言提供的反射机制有所了解。所谓反射,在我看来就是在只知道一个类的名字(字符串形式)的情况下,自动创建出具体的类实例,并且能够枚举该类型拥有的属性、方法等信息。使用反射写出来的代码可以做到异常的精致简洁。

由于我们最近开发的产品使用的是C++语言,然而这种语言并没有内置反射这种机制。于是从网上进行了调研,发现了一些不错的提供C++反射支持的库,如CPP-Reflection、Vlpp、ponder等。我们的产品是用VS2013开发的,对C++11的支持不够完善,这些库一般要用VS2015才能编译。最终我选择了一个叫做RTTR的开源库(Github地址:RTTR传送门),有兴趣的童鞋可以自行编译,这里我提供了使用VS2013编译的x64和x86预编译包。

下面用一个简短的示例演示该库的用法:

Person.h
#include <rttr/type>
 
namespace World
{
    class Person
    {
    public:
        Person();
        ~Person();
 
        void set_name(const std::string& name);
        const std::string& get_name() const;
 
        void set_age(int age);
        int get_age();
 
        virtual void show();
 
        void growupTo(int age=20);
 
    private:
        std::string m_name;
        int m_age;
 
        RTTR_ENABLE()
    };
}
Person.cpp
#include "Person.h"
#include <rttr/registration>
#include <iostream>
 
namespace World
{
    RTTR_REGISTRATION
    {
        rttr::registration::class_<Person>("World::Person")
            .constructor<>()
            (
                rttr::policy::ctor::as_std_shared_ptr
            )
            .property("name", &Person::get_name, &Person::set_name)
            .property("age", &Person::get_age, &Person::set_age)
            .method("show", &Person::show)
            .method("growupTo", &Person::growupTo)
            (
                rttr::default_arguments(18),
                rttr::parameter_names("age")
            )
            ;
    }
 
    Person::Person()
        :m_age(0)
    {
    }
 
 
    Person::~Person()
    {
    }
 
    void Person::set_name(const std::string& name)
    {
        m_name = name;
    }
 
    const std::string& Person::get_name() const
    {
        return m_name;
    }
 
    void Person::set_age(int age)
    {
        m_age = age;
    }
 
    int Person::get_age()
    {
        return m_age;
    }
 
    void Person::show()
    {
        std::cout << "我的名字是: " << m_name << ", 我今年" << m_age << "岁" << std::endl;
    }
 
    void Person::growupTo(int age/* =20 */)
    {
        m_age = age;
        std::cout << m_name << "长到了: " << m_age << "岁" << std::endl;
    }
}

main.cpp
#include <rttr/type>
#include <iostream>
 
int _tmain(int argc, _TCHAR* argv[])
{
    rttr::type t = rttr::type::get_by_name("World::Person");
 
    rttr::variant var = t.create();
 
    rttr::property prop = t.get_property("name");
 
    prop.set_value(var, std::string("小明"));
 
    prop = t.get_property("age");
 
    prop.set_value(var, 18);
 
    rttr::method meth = t.get_method("show");
 
    meth.invoke(var);
 
    std::cout << "属性: " << std::endl;
 
    for (auto& prop : t.get_properties())
    {
        std::cout << "属性名: " << prop.get_name() << ", 属性类性: " << prop.get_type().get_name() << std::endl;
    }
 
    std::cout << "方法: " << std::endl;
 
    for (auto& meth : t.get_methods())
    {
        std::cout << "方法名称: " << meth.get_name() << ", 方法签名: " << meth.get_signature() << std::endl;
        for (auto& info : meth.get_parameter_infos())
        {
            std::cout << "方法参数下标: " << info.get_index() << ", 参数名" << info.get_name() << std::endl;
        }
    }
 
    getchar();
 
    return 0;
}

可以看到,main.cpp中并没有引用Person.h,但却创建出了Person的实例。

有时可能需要将RTTR中的variant转成具体的某个类,可以看到在Person.cpp中的RTTR_REGISTRATION块中,对Person类的构造函数用了rttr::policy::ctor::as_std_shared_ptr的描述,可选的还有rttr::policy::ctor::as_object和rttr::policy::ctor::as_raw_ptr。这三种情况下,代码的书写方式都不一样,详细的可以参见RTTR的官方教程。下面给出各种情况下的转换写法:

    //as_shared_ptr
    //std::shared_ptr<World::Person> person = var.get_value<std::shared_ptr<World::Person>>();
 
    //as_raw_ptr
    //World::Person* person = var.get_value<World::Person*>();
 
    //as_object
    World::Person person = var.get_value<World::Person>();
当然,此时必须要包含Person.h了。
注:若项目编译失败,报了类似error LNK2001: unresolved external symbol "public: static struct rttr::detail::as_object const rttr::policy::ctor::as_object" (?as_object@ctor@policy@rttr@@2U0detail@3@B)的错,需要增加一个预编译宏:RTTR_DLL

----------------------------------------------我是分割线--------------------------------------------------

在实际使用过程中又发现了一些需要注意的问题(一些坑)。我们的项目结构是:首先编译一堆静态链接库(lib),在最终的exe中链接这些文件。有两个问题:

1.这些lib之间也存在引用关系,假设rrtr在lib1中使用,rttr2引用了rtt1,那么在exe中若链接lib1和lib2,若lib2没有定义RTTR_DLL预编译宏的话,会报一个很奇怪的链接错误,因此lib2也需要在项目设置中增加RTTR_DLL。

2.假设在lib1中的class1使用了rttr,然后exe链接lib1,若exe中的所有参与编译的cpp中都没有使用过class1类(包括定义临时变量、全局变量或new一个指针),在根据类名动态创建类时会失败(rttr::type::get_by_name("World::Person"))。我的解决方法是随便找一个参与编译的cpp文件,在文件开头定义一个全局的class1即可。
————————————————
版权声明:本文为CSDN博主「jianingshow」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jianingshow/article/details/52318413

C++实现反射---RTTR库的使用的更多相关文章

  1. AspectCore.Extension.Reflection : .NET Core反射扩展库

    在从零实现AOP的过程中,难免会需要大量反射相关的操作,虽然在.net 4.5+/.net core中反射的性能有了大幅的优化,但为了追求极致性能,自己实现了部分反射的替代方案,包括构造器调用.方法调 ...

  2. c++ 反射类型

    来自: 实现代码=== // // Created by lizhen on 2017/9/29. // #ifndef BOOST_ALL_CALLBACKFUNCTION_H #define BO ...

  3. Java编程的逻辑 (84) - 反射

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  4. Android 插件化开发(一):Java 反射技术介绍

    写在前面:学习插件化开发推荐书籍<Android 插件化开发指南>,本系列博客所整理知识部分内容出自此书. 在之前的项目架构的博文中,我们提到了项目插件化架构,提到插件化架构不得不提的到J ...

  5. Qt 如何使用反射?

    Qt 如何使用反射? c++ 反射 标准库暂时还没有,那我们来看看如何使用 qt 来进行反射. 反射类的案例 1. 通过注册的类型需找 id 进行实例化该类 myclass.h #include &l ...

  6. C#反射的实现

    一,什么是反射? 1,System.Reflection 命名空间中的类与 System.Type 使你能够获取有关加载的程序集和其中定义的类型的信息,如类.接口和值类型. 可以使用反射在运行时创建. ...

  7. 别在重复造轮子了,几个值得应用到项目中的 Java 开源库送给你

    我是风筝,公众号「古时的风筝」.文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面.公众号回复『666』获取高清大图. 风筝我作为一个野路子开发者,直到 ...

  8. robotframework笔记22

    创建测试库 支持的编程语言 机器人框架本身是用写的 Python 和自然的测试 库扩展它可以使用相同的实现 语言. 运行时框架上 Jython ,图书馆也可以 实现使用 Java . 纯Python代 ...

  9. Android Weekly Notes Issue #254

    Android Weekly Issue #254 April 23rd, 2017 Android Weekly Issue #254 本期内容包括: 如何用Kotlin写一个Gradle Plug ...

随机推荐

  1. 微信小程序中途加入云开发之坑

    一开始未使用云开发的小程序项目,之后想使用云开发能力时,要先删除对应在开发者工具中的项目(先压缩备份源码!),再用开发者工具重新创建,很多时候都需要用这种方式进行处理

  2. Codeforces 1503E - 2-Coloring(组合数学)

    Codeforces 题目传送门 & 洛谷题目传送门 考虑什么样的 2-染色方式是符合题目要求的,首先蓝.黄颜色所形成的连通块个数必须 \(\le 2\),否则一定不合法,而显然如果两种颜色连 ...

  3. Atcoder Grand Contest 008 E - Next or Nextnext(乱搞+找性质)

    Atcoder 题面传送门 & 洛谷题面传送门 震惊,我竟然能独立切掉 AGC E 难度的思维题! hb:nb tea 一道 感觉此题就是找性质,找性质,再找性质( 首先看到排列有关的问题,我 ...

  4. 流量限制器(Flux Limiter)

    内容翻译自Wikipedia Flux limiter 流量限制器(Flux limiters)应用在高精度格式中-这种数值方法用来求解科学与工程问题,特别是由偏微分方程(PDE's)描述的流体动力学 ...

  5. 关于单倍型和Phasing

    单倍型,即单倍体基因型,概念很好理解. 单倍型分型的过程就称之Phasing,定相或基因分型. Phasing的意义,在人类疾病遗传和动植物群体遗传中非常重要.也是imputation的必经过程. v ...

  6. Excel-vlookup(查找值,区域范围,列序号,0)如何固定住列序列号,这样即使区域范围变动也不受影响

    突然,发现VLOOKUP的列序列号并不会随着区域范围的改变而自动调节改变,只是傻瓜的一个数,导致V错值.所有,就想实现随表格自动变化的列序号. 方法一:在列序号那里,用函数得出永远想要的那个列在区域范 ...

  7. Excel-电话号码隐藏某几个数为*,起到保护信息作用;

    9.电话号码隐藏某几个数为*,起到保护信息作用: 方法一: =SUBSTITUTE(AG2,MID(AG2,4,5),"*****") 解释函数: MID(目标字符串,裁剪起始位置 ...

  8. Oracle-除了会排序,你对ORDER BY的用法可能一无所知!

    导读 为什么只有ORDER BY后面可以使用列别名 为什么不推荐使用ORDER BY后接数字来排序 为什么视图和子查询里面不能使用ORDER BY -- ​小伙伴们在进行SQL排序时,都能很自然的使用 ...

  9. 日常Java 2021/11/21

    Java文档注释 Java支持三种注释方式.前两种分别是Ⅱ和/产*,第三种被称作说明注释,它以产开始,以*I结束.说明注释允许你在程序中嵌入关于程序的信息.你可以使用javadoc工具软件来生成信息, ...

  10. Git提交规范

    Commit message 的格式 每次提交,Commit message 都包括三个部分:Header,Body 和 Footer. <type>(<scope>): &l ...