前述
反射的概念是,比如有一个类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语言编程过程中的应用。
PREVIOUSc++模拟实现defer
NEXTgitalk配置