C++实现反射---RTTR库的使用
使用过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库的使用的更多相关文章
- AspectCore.Extension.Reflection : .NET Core反射扩展库
在从零实现AOP的过程中,难免会需要大量反射相关的操作,虽然在.net 4.5+/.net core中反射的性能有了大幅的优化,但为了追求极致性能,自己实现了部分反射的替代方案,包括构造器调用.方法调 ...
- c++ 反射类型
来自: 实现代码=== // // Created by lizhen on 2017/9/29. // #ifndef BOOST_ALL_CALLBACKFUNCTION_H #define BO ...
- Java编程的逻辑 (84) - 反射
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- Android 插件化开发(一):Java 反射技术介绍
写在前面:学习插件化开发推荐书籍<Android 插件化开发指南>,本系列博客所整理知识部分内容出自此书. 在之前的项目架构的博文中,我们提到了项目插件化架构,提到插件化架构不得不提的到J ...
- Qt 如何使用反射?
Qt 如何使用反射? c++ 反射 标准库暂时还没有,那我们来看看如何使用 qt 来进行反射. 反射类的案例 1. 通过注册的类型需找 id 进行实例化该类 myclass.h #include &l ...
- C#反射的实现
一,什么是反射? 1,System.Reflection 命名空间中的类与 System.Type 使你能够获取有关加载的程序集和其中定义的类型的信息,如类.接口和值类型. 可以使用反射在运行时创建. ...
- 别在重复造轮子了,几个值得应用到项目中的 Java 开源库送给你
我是风筝,公众号「古时的风筝」.文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面.公众号回复『666』获取高清大图. 风筝我作为一个野路子开发者,直到 ...
- robotframework笔记22
创建测试库 支持的编程语言 机器人框架本身是用写的 Python 和自然的测试 库扩展它可以使用相同的实现 语言. 运行时框架上 Jython ,图书馆也可以 实现使用 Java . 纯Python代 ...
- Android Weekly Notes Issue #254
Android Weekly Issue #254 April 23rd, 2017 Android Weekly Issue #254 本期内容包括: 如何用Kotlin写一个Gradle Plug ...
随机推荐
- 解决fatal: unable to access '': Failed to connect to 127.0.0.1 port 1181: Connection refused的问题
今天把项目提交的git远程的时候遇到一个问题 fatal: unable to access '': Failed to connect to 127.0.0.1 port 1181: Connect ...
- Codeforces 986E - Prince's Problem(树上前缀和)
题面传送门 题意: 有一棵 \(n\) 个节点的树,点上有点权 \(a_i\),\(q\) 组询问,每次询问给出 \(u,v,w\),要求: \(\prod\limits_{x\in P(u,v)}\ ...
- 【豆科基因组】绿豆Mungbean, Vigna radiata基因组2014NC
目录 来源 一.简介 二.结果 基因组组装 重复序列和转座子 基因组特征和基因注释 绿豆的驯化 豆科基因组复制历史 基于转录组分析的豇豆属形成 绿豆育种基因组资源 三.讨论 四.方法 材料 组装 SN ...
- R合并数据框有重复匹配时只保留第一行
前言 合并数据框有重复匹配时通常会返回所有的匹配,如何只保留匹配的第一行呢?其实这个需求也很常见.如芯片探针ID和基因ID往往多对一,要合并ID对应矩阵和芯片表达矩阵时. 数据例子 data = da ...
- python16线程
python对于I/O密集型应用比较好,具体根据是什么类型应用来查看 对于cpu密集型应用可以借助python的一些扩展去实现 thread模块是比较早期的模块,thresding是比较新的模块,对t ...
- getdelim函数
利用getdelim函数分割读取字段,将文件制表符替换为空格符 1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main( ...
- linux中对errno是EINTR的处理
慢系统调用(slow system call):此术语适用于那些可能永远阻塞的系统调用.永远阻塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类.如:若没有客户连接到服务器上,那么服 ...
- Linux 软件安装位置选择指南
Linux 软件安装 Linux 下安装软件不像 Windows 下安装这么简单,Windows 下会自动选择合适安装路径,而 Linux 下安装路径大部分完全由自己决定,我可以将软件安装到任意可 ...
- 大数据学习day19-----spark02-------0 零碎知识点(分区,分区和分区器的区别) 1. RDD的使用(RDD的概念,特点,创建rdd的方式以及常见rdd的算子) 2.Spark中的一些重要概念
0. 零碎概念 (1) 这个有点疑惑,有可能是错误的. (2) 此处就算地址写错了也不会报错,因为此操作只是读取数据的操作(元数据),表示从此地址读取数据但并没有进行读取数据的操作 (3)分区(有时间 ...
- windows下 apache 二级域名相关配置 【转】
转至: http://www.th7.cn/Program/php/201306/141305.shtml 今天给大家总结下 windows 下 apache的二级域名的相关配置 下面就利用本地127 ...