You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求可快速实现自定义类型序列化反序列化的C++反射库

满足需求的C++反射方案推荐与实现示例

核心思路

要实现类似Unity的组件序列化,需具备两个核心能力:

  1. 运行时类型实例化:根据字符串(如"Mesh")创建对应具体类的实例,而非基类指针
  2. 属性遍历与自动赋值:能获取类的所有属性,读取YAML节点值并自动转换类型赋值

以下是几种无需大量代码即可实现的方案,结合YAML-CPP完成你的需求:


方案1:Boost.PFR + 工厂模式(编译时反射,轻量无冗余)

Boost.PFR是轻量编译时反射库,无需额外宏定义即可遍历结构体/类的公共成员,配合工厂模式实现运行时实例化。

步骤1:组件定义与工厂注册

#include <boost/pfr.hpp>
#include <yaml-cpp/yaml.h>
#include <unordered_map>
#include <memory>

// 组件基类
struct IComponent {
    virtual ~IComponent() = default;
    virtual void deserialize(const YAML::Node& node) = 0;
};

// Mesh组件实现
struct Mesh : IComponent {
    std::vector<float> Vertices;
    std::vector<int> Indices;
    std::string Path;

    void deserialize(const YAML::Node& node) override {
        // 遍历所有成员自动赋值
        boost::pfr::for_each_field(*this, [&](auto& field, auto idx) {
            constexpr auto propName = boost::pfr::get_name<idx>(*this);
            if (node[propName]) {
                field = node[propName].as<std::decay_t<decltype(field)>>();
            }
        });
    }
};

// 组件工厂
class ComponentFactory {
public:
    using Creator = std::unique_ptr<IComponent>(*)();
    
    static void registerComponent(const std::string& name, Creator creator) {
        getCreators()[name] = creator;
    }

    static std::unique_ptr<IComponent> create(const std::string& name) {
        auto it = getCreators().find(name);
        return it != getCreators().end() ? it->second() : nullptr;
    }

private:
    static std::unordered_map<std::string, Creator>& getCreators() {
        static std::unordered_map<std::string, Creator> creators;
        return creators;
    }
};

// 注册组件的宏
#define REGISTER_COMPONENT(T) \
    struct Register##T { \
        Register##T() { \
            ComponentFactory::registerComponent(#T, []() { return std::make_unique<T>(); }); \
        } \
    }; \
    static Register##T register_##T;

REGISTER_COMPONENT(Mesh)

步骤2:反序列化实现(对应你的伪代码)

int main() {
    YAML::Node node = YAML::LoadFile("scene.yaml");
    std::string componentName = node["Scene Object"]["Component"].as<std::string>();

    // 生成具体Mesh实例而非IComponent
    auto component = ComponentFactory::create(componentName);
    if (!component) {
        // 处理类型不存在的异常
        return 1;
    }

    // 自动完成属性赋值
    component->deserialize(node["Scene Object"]["Component"]);

    // 如需访问具体类型成员,用dynamic_cast转换
    if (auto mesh = dynamic_cast<Mesh*>(component.get())) {
        // 操作mesh->Vertices、mesh->Path等成员
    }

    return 0;
}

方案2:C++20标准反射(无第三方依赖,需最新编译器)

C++20引入的标准反射(GCC 13+/Clang 16+支持),无需第三方库即可实现反射功能。

实现示例

#include <reflect>
#include <yaml-cpp/yaml.h>
#include <unordered_map>
#include <memory>

struct IComponent {
    virtual ~IComponent() = default;
    virtual void deserialize(const YAML::Node& node) = 0;
};

struct Mesh : IComponent {
    std::vector<float> Vertices;
    std::vector<int> Indices;
    std::string Path;

    void deserialize(const YAML::Node& node) override {
        using namespace std::reflect;
        // 遍历类的所有公共成员
        for_each(get_members<Mesh>(), [&](auto member) {
            std::string propName = get_name(member);
            if (node[propName]) {
                get(member, *this) = node[propName].as<decltype(get(member, *this))>();
            }
        });
    }
};

// 工厂注册部分同方案1,省略重复代码
REGISTER_COMPONENT(Mesh)

int main() {
    YAML::Node node = YAML::LoadFile("scene.yaml");
    std::string componentName = node["Scene Object"]["Component"].as<std::string>();
    
    auto component = ComponentFactory::create(componentName);
    if (component) {
        component->deserialize(node["Scene Object"]["Component"]);
    }
    return 0;
}

方案3:自定义轻量反射宏(完全可控,无第三方依赖)

如果不想依赖任何外部库,可以自己实现简单的反射宏,手动注册类的属性信息。

实现示例

#include <yaml-cpp/yaml.h>
#include <unordered_map>
#include <memory>
#include <vector>
#include <functional>

struct IComponent {
    virtual ~IComponent() = default;
    virtual void deserialize(const YAML::Node& node) = 0;
};

// 属性反射信息结构体
struct PropertyInfo {
    std::string name;
    std::function<void(IComponent*, const YAML::Node&)> setter;
};

// 组件元数据
struct ComponentMeta {
    std::function<std::unique_ptr<IComponent>()> creator;
    std::vector<PropertyInfo> properties;
};

// 全局元数据注册表
std::unordered_map<std::string, ComponentMeta>& getComponentMeta() {
    static std::unordered_map<std::string, ComponentMeta> meta;
    return meta;
}

// 自定义反射宏
#define BEGIN_COMPONENT(T) \
    struct T : IComponent { \
        void deserialize(const YAML::Node& node) override { \
            auto& meta = getComponentMeta()[#T]; \
            for (auto& prop : meta.properties) { \
                if (node[prop.name]) { \
                    prop.setter(this, node[prop.name]); \
                } \
            } \
        }

#define REGISTER_PROPERTY(T, Type, Prop) \
    Type Prop; \
    static void set##Prop(IComponent* comp, const YAML::Node& node) { \
        static_cast<T*>(comp)->Prop = node.as<Type>(); \
    }

#define END_COMPONENT(T) \
    }; \
    struct Register##T { \
        Register##T() { \
            getComponentMeta()[#T] = { \
                []() { return std::make_unique<T>(); }, \
                { \
                    {"Vertices", setVertices}, \
                    {"Indices", setIndices}, \
                    {"Path", setPath} \
                } \
            }; \
        } \
    }; \
    static Register##T register_##T;

// 使用宏定义Mesh组件
BEGIN_COMPONENT(Mesh)
REGISTER_PROPERTY(Mesh, std::vector<float>, Vertices)
REGISTER_PROPERTY(Mesh, std::vector<int>, Indices)
REGISTER_PROPERTY(Mesh, std::string, Path)
END_COMPONENT(Mesh)

// 生成组件的函数
std::unique_ptr<IComponent> generateComponentFromComponentName(const std::string& name) {
    auto it = getComponentMeta().find(name);
    return it != getComponentMeta().end() ? it->second.creator() : nullptr;
}

int main() {
    YAML::Node node = YAML::LoadFile("scene.yaml");
    std::string componentName = node["Scene Object"]["Component"].as<std::string>();

    auto component = generateComponentFromComponentName(componentName);
    if (component) {
        component->deserialize(node["Scene Object"]["Component"]);
    }

    return 0;
}

选择建议

  • 若使用C++20且编译器支持标准反射,优先选方案2,符合标准且无第三方依赖。
  • 若需兼容旧C++标准,方案1的Boost.PFR最省心,无需手动维护属性列表,编译时反射性能优异。
  • 若完全不想依赖外部库,方案3的自定义宏可完全控制反射逻辑,但需手动维护属性注册列表。

内容的提问来源于stack exchange,提问作者Davide Paolillo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 06:18:24