c++反射实现

 

前述

反射的概念是,比如有一个类ClassA,你想通过它的名称”ClassA”来创建一个ClassA的实例,这就叫反射。

反射在很多业务场景/框架下是非常实用的,可以大大降低业务的代码量,框架看起来也比较清晰。

c++是没有其他语言的反射机制的,只能靠手动实现。实际上就是实现一个类名称到类实例(或者创建类实例对象的函数)的一个映射。

实现

全局静态注册方法

维护一个全局静态map,在进入main之前,就将需要反射的类注册好,需要使用时获取即可。

// 实现
typedef void* (*ReflectFunc)(void);

static std::map<std::string, ReflectFunc> _reflection_map;

class HandlerRegister {
public:
    HandlerRegister(const std::string& name, ReflectFunc func) {
        _reflection_map.insert(std::make_pair(name, func));
    }
};

#define REGISTER(className)                                       \
    className* objectCreator##className(){                              \
        return new className;                                           \
    }                                                                   \
    HandlerRegister g_creatorRegister##className(                        \
        #className,(ReflectFunc)objectCreator##className)


// 使用方式
class Test {
public:
    Test() { std::cout << "Test constructor." << std::endl; }
    ~Test() { std::cout << "Test destructor." << std::endl; }
};

REGISTER(Test);

int main() {
    // 需要时从map中取即可 也可再用类封装一下
    return 0;
}

工厂类内注册方法

用一个工厂类存储映射的map,在main中进行初始化,将需要反射的类注册好,需要使用时获取即可。

// 实现
#include <iostream>
#include <memory>
#include <typeinfo>
#include <cxxabi.h>
#include <map>

typedef void* (*ReflectFunc)(void);


class ClassFactory {
public:
    ClassFactory() {}
    ~ClassFactory() {}

public:
    virtual int Init() = 0;

    template <class T>
    void Regist() {
        HandlerRegister(
            abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr),
            (ReflectFunc)ReflectFuncPointer<T>
        );
    }

    void* Create(const std::string& class_name) {
        auto iter = reflection_map_.find(class_name);
        if (iter != reflection_map_.end()) {
            return iter->second();
        }
        return nullptr;
    }

private:
    template <class T>
    static T* ReflectFuncPointer() {
        return new T;
    }

    void HandlerRegister(const std::string& name, ReflectFunc pCreate) {
        reflection_map_.insert(std::make_pair(name, pCreate));
    }

private:
    std::map<std::string, ReflectFunc> reflection_map_;
};

// 使用方式
class Base {
public:
    Base() {}
    virtual ~Base() {}
};

class Test : public Base {
public:
    Test() { std::cout << "Test constructor." << std::endl; }
    ~Test() { std::cout << "Test destructor." << std::endl; }
};

class TestFactory : public ClassFactory {
public:
    int Init() override {
        Regist<Test>();
        return 0;
    }
};

int main() {
    TestFactory factory;
    factory.Init();
    // 为何要采用继承的方式:
    // 1. 方便对指针进行显式操作: 假设自己并不清楚这字符串对应的是什么类的情况下
    // 2. void*指针不会运行类的析构函数,为了代码方便展示因此采用继承方式~
    std::shared_ptr<Base> test_pointer(static_cast<Base*>(factory.Create("Test")));
    // do sth.
    return 0;
}

// 运行结果:
Test constructor.
Test destructor.

总结

总而言之,c语言并不能实现真正的反射,每一个需要达成反射的类,必须先经过注册过程。但是这并不妨碍反射机制在c语言编程过程中的应用。