以下是基于纯C++标准(仅依赖g++编译器)的反射机制入门详解,包含三种可编译的实用方案,每种方案均提供完整代码和编译命令:


🔧 一、工厂模式+注册宏(动态创建对象)

适用场景:插件系统、动态加载类
原理:全局映射表存储类名与构造函数,通过字符串实例化对象
代码示例(C++11起支持):

#include <iostream>
#include <unordered_map>
#include <functional>
#include <memory>

class Factory {
    using Creator = std::function<std::unique_ptr<void>()>;
    static std::unordered_map<std::string, Creator> registry;
public:
    static void registerClass(const std::string& name, Creator fn) {
        registry[name] = fn;
    }
    
    template <typename T>
    static std::unique_ptr<T> create(const std::string& name) {
        auto it = registry.find(name);
        if (it != registry.end()) {
            auto basePtr = it->second();
            void* rawPtr = basePtr.release();
            return std::unique_ptr<T>(static_cast<T*>(rawPtr));
        }
        return nullptr;
    }
};

std::unordered_map<std::string, Factory::Creator> Factory::registry;

// 自动注册宏(在main前初始化)
#define REGISTER_CLASS(ClassName) \
namespace { \
    struct ClassName##Register { \
        ClassName##Register() { \
            Factory::registerClass(#ClassName, []() -> std::unique_ptr<void> { \
                return std::unique_ptr<void>(new ClassName()); \
            }); \
        } \
    }; \
    static ClassName##Register ClassName##_register; \
}

// 测试类
class MyClass {
public:
    void print() { std::cout << "MyClass created\n"; }
};

REGISTER_CLASS(MyClass)  // 注册

int main() {
    auto obj = Factory::create<MyClass>("MyClass");
    if (obj) obj->print();  // 输出:MyClass created
    return 0;
}

编译命令(需C++11):

g++ -std=c++11 -o reflect factory.cpp

🧠 二、编译时反射(类型信息查询)

适用场景:序列化框架、代码生成
原理:模板特化+constexpr在编译时生成类型元数据
代码示例(C++17起支持):

#include <iostream>
#include <string_view>

// 反射模板基类
template <typename T>
struct Reflect {
    static constexpr size_t member_count = 0;
    static constexpr std::string_view member_name(size_t) { return ""; }
};

// 目标类
struct Person {
    int age;
    std::string name;
};

// 特化Person的反射信息
template <>
struct Reflect<Person> {
    static constexpr size_t member_count = 2;
    static constexpr std::string_view member_name(size_t i) {
        constexpr std::string_view names[] = {"age", "name"};
        return (i < member_count) ? names[i] : "";
    }
};

// 打印类型信息
template <typename T>
void print_type_info() {
    std::cout << "Members of " << typeid(T).name() << ":\n";
    for (size_t i = 0; i < Reflect<T>::member_count; ++i) {
        std::cout << " - " << Reflect<T>::member_name(i) << "\n";
    }
}

int main() {
    print_type_info<Person>();
    // 输出:
    // Members of Person:
    //  - age
    //  - name
    return 0;
}

编译命令(需C++17):

g++ -std=c++17 -o reflect compile_time.cpp

📦 三、成员变量映射(运行时属性访问)

适用场景:对象序列化、动态属性查看器
原理:基类维护成员指针映射表
代码示例(C++11起支持):

#include <iostream>
#include <string>
#include <unordered_map>

class Reflectable {
protected:
    std::unordered_map<std::string, void*> property_map;
public:
    template <typename T>
    void register_property(const std::string& name, T& prop) {
        property_map[name] = &prop;
    }
    
    void print_property(const std::string& name) {
        if (auto it = property_map.find(name); it != property_map.end()) {
            std::cout << name << " = " << *(static_cast<std::string*>(it->second)) << "\n";
        }
    }
};

class User : public Reflectable {
public:
    std::string username;
    int id;
    
    User() : username(""), id(0) {
        register_property("username", username);
        // 扩展点:可添加其他属性注册
    }
};

int main() {
    User user;
    user.username = "Alice";
    user.print_property("username");  // 输出:username = Alice
    return 0;
}

编译命令

g++ -std=c++11 -o reflect member_map.cpp

⚖️ 方案对比与选型建议

方案 技术特点 适用场景 编译要求
工厂模式+注册宏 运行时动态创建对象 插件系统、动态加载 C++11
编译时反射 零运行时开销,类型安全 序列化框架、代码生成器 C++17
成员变量映射 显式注册属性,灵活性高 对象序列化、属性查看器 C++11

⚠️ 避坑指南

  1. 全局静态变量初始化顺序:工厂模式中注册宏需在main前执行(利用静态变量初始化机制)
  2. 类型安全:工厂模式中static_cast转换需确保类型匹配,否则UB
  3. 编译时反射限制:无法获取运行时对象值,仅适合类型元数据
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐