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 ...
随机推荐
- 对于cmd命令的一些常用用法
cmd命令是当今比较常见的主机命令,对于一些文件的执行和后台数据的控制有着比较有效的规范. 现在就讲几个比较常见的命令. IP查询 按住window+r 进入控制台,在输入cmd命令.在弹出的 cmd ...
- Protocol Buffer序列化Java框架-Protostuff
了解Protocol Buffer 首先要知道什么是Protocol Buffer,在编程过程中,当涉及数据交换时,我们往往需要将对象进行序列化然后再传输.常见的序列化的格式有JSON,XML等,这些 ...
- Java设计模式之(十三)——模板方法模式
1.什么是模板模式? Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. ...
- jumpserver——脚本安装
CentOS Linux release 7.7.1908 (Core) 3.10.0-1062.4.1.el7.x86_64 Initialize(){ yum update -y systemct ...
- Tikz绘制形似万花尺的图片
初中时意外发现数学课本上有这么一个好玩的图 大概就是把两条相等线段A.B分为10个小段并在点上标序号,A线段1点连B线段9点,2点连8点,依次类推. 假设有这么一个框架图 按照第一张图的方式进一步绘图 ...
- Spring Boot 热启动插件
1. maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId ...
- adverb
An adverb is a word or an expression that modifies a verb, adjective, another adverb, determiner [限定 ...
- day06 模板层
day06 模板层 今日内容 常用语法 模板语法传值 模板语法之过滤器 模板语法之标签 自定义过滤器.标签.inclusion_tag(BBS作业用一次) 模板的继承(django前后端结合 那么使用 ...
- Flume(四)【配置文件总结】
目录 一.Agent 二.Source taildir arvo netstat exec spooldir 三.Sink hdfs kafka(待续) hbase(待续) arvo logger 本 ...
- C++构造函数和析构函数初步认识(2)
构造函数的三个作用1.构造对象2.对象初始化3.类型转换 //Test1.h #include<iostream> using namespace std; //构造对象 //初始化对象 ...