UDRefl: 一个基于C++20的高性能动态反射库

目录

1.简介

2.核心概念

3.安装与集成

4.使用详解

4.1.注册流程

4.2.使用流程

4.3.完整示例

5.应用场景

6.与其他反射库对比

7.注意事项

8.总结


1.简介

UDRefl (Ubpa Dynamic Reflection)是一个基于C++20高性能动态反射库,由 Ubpa 开发并开源(MIT 许可证)。它提供了在运行时灵活访问和操作 C++ 类型结构的能力,无需依赖 RTTI(运行时类型信息)或异常处理机制,采用无污染头文件设计,显著提升编译效率。UDRefl 的核心优势在于极致性能和强大功能,同时保持简洁易用的 API,特别适合需要动态类型操作的场景,如插件系统、序列化 / 反序列化、脚本绑定等。

核心特征:

  • 极致性能:采用编译期模板元编程和高效数据结构,反射操作几乎无额外运行时开销
  • 完全动态:无需 RTTI 和异常,纯标准 C++20 实现,不依赖外部工具或编译器扩展
  • 零头文件污染:反射信息在.cpp 文件中生成,修改数据时最小化编译时间
  • 全面类型支持
    • 单继承、多继承和虚拟继承
    • 构造函数、析构函数、赋值运算符
    • 虚函数、纯虚函数、重载函数、任意参数数量的方法
    • 全局域、方法和枚举
    • 指针、引用、数组、标准容器、迭代器
  • 高级功能
    • 方法调用时自动参数类型转换
    • 可在任意类层次调用方法
    • 为所有反射对象添加额外属性
    • 无需类型声明即可操作自定义类型(适合插件系统)
    • 元函数支持(operator+、operator-、begin/end 等)
    • 自举能力(将 UDRefl 接口注册到自身中)

2.核心概念

概念 描述
ReflMngr 库的核心管理器,负责注册和管理所有类型信息、域、方法和属性,提供主要接口
TypeInfo 类型信息结构体,包含类型大小、对齐、多态性、域信息、方法信息、基类信息和属性集
ObjectView 对象视图,包含对象指针 (void*) 和类型 (Type),不管理资源,类似 std::string_view
SharedObject 对象视图的子类,多了 std::shared_ptr<void>来管理对象生命周期
Field/FieldPtr 域表示类型的成员对象,FieldPtr 用于获取变量指针,支持 5 种类型(基本、虚拟、静态、动态共享、动态缓冲)
Method/MethodPtr 方法表示类型的成员函数,MethodPtr 用于调用成员函数,支持变量方法、常量方法和静态方法
Attr (属性) 附加信息,是一个共享对象,可附加到类型、域或方法上,按 Type 索引
Name 字符视图 (std::string_view)+ 哈希值,用于高效查找类型、域和方法
Type 类型名 (std::string_view)+ 哈希值,支持类型计算(如添加 const、引用等修饰)

核心API:

功能 API 用法
获取反射管理器 ReflMngr::Instance()
注册类型 mngr.RegisterType<T>()
注册成员变量 mngr.AddField<&T::成员>("名称")
注册成员方法 mngr.AddMethod<&T::方法>("名称")
动态创建对象 mngr.MakeShared(Type_of<T>)
访问变量 obj.Var("变量名")
调用方法 obj.Invoke("方法名", 参数...)
类型转换 obj.Var("x").As<int>()
遍历成员 FieldRange_of<T>()

3.安装与集成

1.下载源码

git clone https://github.com/Ubpa/UDRefl.git

2.CMake 编译生成 VS 工程

  • 打开 x64 Native Tools Command Prompt for VS 2022(VS 自带命令行)
  • 进入 UDRefl 源码根目录,执行命令:
cpp 复制代码
# 创建编译文件夹
mkdir build
cd build

# 生成 VS2022 工程(64位)
cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_STANDARD=20

3.VS 编译库文件

  • 进入 build 文件夹,打开 UDRefl.sln
  • 切换模式:Debug / Release(建议都编译一次)
  • 右键解决方案 → 生成解决方案
  • 编译成功后,会生成:
    • 头文件:源码根目录/include
    • 库文件:build/lib/Debug/UDRefl.lib / build/lib/Release/UDRefl.lib

4.使用详解

4.1.注册流程

UDRefl 的使用主要分为注册使用两个步骤:

1.注册类型 :使用ReflMngr::RegisterType<T>()模板函数,自动获取类型名、大小和对齐

cpp 复制代码
ReflMngr::RegisterType<Vec>();

2.注册域 :使用AddField模板函数,支持自动识别域类型

cpp 复制代码
Mngr.AddField<&Vec::x>("x");
Mngr.AddField<&Vec::y>("y");
Mngr.AddField<&Vec::y_static>(Type_of<Vec>, "y_static");

3.注册方法 :使用AddMethod模板函数,支持重载函数(通过MemFuncOf解决)

cpp 复制代码
Mngr.AddMethod<&Vec::norm>("norm");
Mngr.AddMethod<MemFuncOf<Funcs, void()>>::get(&Funcs::bar)>("bar");
Mngr.AddMethod<&Funcs::cat>(Type_of<Funcs>, "cat");

4.注册基类 :使用AddBases模板函数,自动处理继承关系(包括虚继承)

cpp 复制代码
Mngr.AddBases<D, B, C>();

5.注册属性 :在注册类型、域或方法时附加属性,或使用AddTypeAttr/AddFieldAttr/AddMethodAttr接口

4.2.使用流程

1.创建对象 :使用MakeShared创建共享对象

cpp 复制代码
SharedObject v = Mngr.MakeShared(Type_of<Vec>);

2.访问变量 :使用Var方法获取变量,支持直接赋值和读取

cpp 复制代码
v.Var("x") = 3;
v.Var("y") = 4;
std::cout << "x: " << v.Var("x") << std::endl;

3.调用方法 :使用Invoke方法调用对象方法,支持自动参数转换

cpp 复制代码
std::cout << "norm: " << v.Invoke("norm") << std::endl;

4.遍历成员 :使用FieldRange_ofMethodRange_of遍历类型的域和方法

cpp 复制代码
for (auto&& [name, info] : FieldRange_of<Vec>)
  std::cout << name.GetView() << std::endl;

5.元函数操作:支持运算符重载和容器接口,简化代码

cpp 复制代码
// 运算符
SharedObject sum = v1 + v2;

// 容器遍历
for(auto elem : v_container) { /*...*/ }

6.类型运算:支持添加 const、引用、指针等类型修饰

cpp 复制代码
ObjectView const_v = v.AddConst();
ObjectView ref_v = v.AddLValueReference();

4.3.完整示例

我们创建一个 Person 类,演示类型注册、成员访问、方法调用、遍历成员,这是 UDRefl 最核心的用法。

cpp 复制代码
#include <iostream>
#include <string>
// 必须包含的头文件
#include <UDRefl/UDRefl.h>

// 使用命名空间(简化代码)
using namespace Ubpa::UDRefl;
using namespace std;

// ===================== 1. 定义普通类(无任何反射宏,零污染)=====================
struct Person {
    string name;   // 成员变量
    int age;        // 成员变量

    // 成员方法
    void SayHello() {
        cout << "Hello! 我是" << name << ",今年" << age << "岁" << endl;
    }

    // 带参数的方法
    void SetAge(int a) {
        age = a;
    }
};

// ===================== 2. 注册类型(必须在cpp中注册,头文件无侵入)=====================
void RegisterPerson() {
    auto& mngr = ReflMngr::Instance(); // 获取反射管理器单例

    // 1. 注册 Person 类型
    mngr.RegisterType<Person>();

    // 2. 注册成员变量
    mngr.AddField<&Person::name>("name");
    mngr.AddField<&Person::age>("age");

    // 3. 注册成员方法
    mngr.AddMethod<&Person::SayHello>("SayHello");
    mngr.AddMethod<&Person::SetAge>("SetAge");
}

// ===================== 3. 使用反射操作对象 =====================
int main() {
    // 第一步:注册类型(程序初始化时执行一次)
    RegisterPerson();
    auto& mngr = ReflMngr::Instance();

    // ===================== 基础用法 =====================
    // 1. 动态创建 Person 对象(智能指针,自动管理内存)
    SharedObject p = mngr.MakeShared(Type_of<Person>);

    // 2. 动态赋值成员变量
    p.Var("name") = "小明";
    p.Var("age") = 20;

    // 3. 动态获取成员变量
    cout << "姓名:" << p.Var("name").As<string>() << endl;
    cout << "年龄:" << p.Var("age").As<int>() << endl;

    // 4. 动态调用成员方法
    p.Invoke("SayHello");       // 无参方法
    p.Invoke("SetAge", 25);     // 带参方法
    p.Invoke("SayHello");

    // ===================== 高级用法:遍历成员 =====================
    cout << "\n=== 遍历 Person 所有成员变量 ===" << endl;
    for (auto&& [name, field] : FieldRange_of<Person>) {
        cout << "成员名:" << name.ToString() << endl;
    }

    return 0;
}

输出:

cpp 复制代码
姓名:小明
年龄:20
Hello! 我是小明,今年20岁
Hello! 我是小明,今年25岁

=== 遍历 Person 所有成员变量 ===
成员名:name
成员名:age

5.应用场景

  • 插件系统:无需类型声明即可操作插件中的自定义类型,实现动态扩展
  • 序列化 / 反序列化:自动遍历对象成员,实现高效的数据序列化和反序列化
  • 脚本绑定:将 C++ 类和方法注册到脚本语言(如 Lua),通过反射实现脚本与 C++ 的交互
  • 动态 UI 生成:根据对象类型信息自动生成属性编辑器,适用于游戏编辑器等工具
  • 依赖注入:通过反射自动创建对象并注入依赖,实现松耦合架构
  • 单元测试:通过反射自动调用测试方法,生成测试报告

6.与其他反射库对比

特性 UDRefl RTTR Boost.Reflect
C++ 标准 C++20 C++11+ C++11+
依赖 无(纯标准 C++) Boost 库
RTTI / 异常 不需要 需要 需要
性能 极高(编译期优化)
头文件污染 无(反射信息在.cpp)
多继承 / 虚继承 支持 支持 有限支持
元函数支持 完整 部分
自举能力 支持 不支持 不支持

7.注意事项

  1. C++20 要求:必须使用支持 C++20 的编译器,如 GCC 10+、Clang 10 + 或 MSVC 2019 16.8.5+
  2. 资源管理ObjectView不管理资源,需确保指向的对象生命周期长于视图本身
  3. 多线程安全ReflMngr的注册操作应在单线程初始化阶段完成,运行时访问是线程安全的
  4. 动态域:动态域分为共享和缓冲两种类型,缓冲域只能存储简单类型
  5. 方法调用:调用虚函数时会自动解析正确的函数地址,支持多态调用

8.总结

UDRefl 是 C++20 生态中一款极具价值的动态反射库,它以极致性能、零依赖和强大功能为核心优势,为 C++ 开发者提供了运行时类型操作的高效解决方案。其简洁的 API 设计和完善的文档支持,降低了反射技术的使用门槛,特别适合需要动态类型操作的中大型项目。无论是开发插件系统、序列化框架还是脚本绑定层,UDRefl 都能显著提升开发效率和代码质量。

相关推荐
前进吧-程序员3 小时前
C++20 Concepts 简明介绍:模板编程的“合约时代”
c++20
w我是东山啊18 天前
C++20——协程
c++20
wangjialelele19 天前
C++11、C++14、C++17、C++20新特性解析(一)
linux·c语言·开发语言·c++·c++20·visual studio
telllong20 天前
C++20 Modules:从入门到真香
java·前端·c++20
WarPigs1 个月前
基于泛型+反射的Excel万能导表工具
unity·c#·excel·反射
Max_uuc2 个月前
【架构心法】逃离回调地狱:从 Protothreads 到 C++20 协程 (Coroutines) 的嵌入式进化
c++20
程序喵大人2 个月前
C++未来展望:模块、协程、反射如何改变我们编写代码的方式?还是说C++要被淘汰?
开发语言·c++·协程·反射·模板
阿猿收手吧!2 个月前
【C++】C++20协程的await_transform和coroutine_handle
开发语言·c++·c++20
阿猿收手吧!2 个月前
【C++】 co_yield如何成为语法糖?解析其背后的Awaitable展开与协程状态跃迁
c++·c++20