来自:
实现代码===
// // Created by lizhen on 2017/9/29. // #ifndef BOOST_ALL_CALLBACKFUNCTION_H #define BOOST_ALL_CALLBACKFUNCTION_H #include <iostream> #include <map> #include <string> using namespace std; typedef void* (*PTRCreateObject)(void);//定义一个函数指针类型,用于指向创建类实例的回调函数 class ClassFactory{ private: map<string,PTRCreateObject >map_classMap; ClassFactory(){}; public: void *getClassByName(string className); void registClass(string name,PTRCreateObject method); static ClassFactory& getInstance(); }; ClassFactory& ClassFactory::getInstance() { static ClassFactory sLo_factory; return sLo_factory; } void* ClassFactory::getClassByName(string className) { map<string,PTRCreateObject >::const_iterator iter; iter = map_classMap.find(className); if(iter==map_classMap.end()){ return NULL; }else{ return iter->second(); } } void ClassFactory::registClass(string name, PTRCreateObject method) { map_classMap.insert(pair<string,PTRCreateObject>(name,method)); } class RegisterAction{ public: RegisterAction(string className,PTRCreateObject ptrCreateFn){ ClassFactory::getInstance().registClass(className,ptrCreateFn); } }; //================================ClassA class TestClassA{ public: void m_print(){ cout<<"hello TestClassA"<<endl; } }; TestClassA* createObjTestClassA(){ return new TestClassA(); } RegisterAction g_create_RegisterTestClassA("TestClassA",(PTRCreateObject)createObjTestClassA()); //<----- //================================ClassB //test class B class TestClassB{ public: void m_print(){ cout<<"hello TestClassB"<<endl; } }; TestClassB* createObjTestClassB(){ return new TestClassB(); } RegisterAction g_create_RegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB()); //<--- #define REGISTER(className) \ className* objectCreater##className(){ \ return new className(); \ } \ RegisterAction g_createrRegister##className( \ #className,(PTRCreateObject)objectCreater##className) class classC{ public: void m_print(){ std::cout<<"hello classC"<<std::endl; } }; REGISTER(classC); class Reflact{ public: void run(){ TestClassA* ptrObjA = (TestClassA*)ClassFactory::getInstance().getClassByName("TestClass"); ptrObjA->m_print(); //REGISTER(classC); classC* ptr_c = (classC*)ClassFactory::getInstance().getClassByName("classC"); ptr_c->m_print(); } }; #endif //BOOST_ALL_CALLBACKFUNCTION_H
=====
转自http://blog.csdn.net/brighlee/article/details/72885219
前言
反射的概念:
指程序在运行时,访问、检测和修改它本身状态或行为的一种能力。wikipedia
简单的来说,就是一种自描述和自控制的能力。如果联想到镜子,就可以很好的理解,你能通过镜子看到自己,包括自己的动作,自己的外表。唯一不同的地方是,计算机语言的反射能力还包含对看到的自己采取措施。
反射的作用
在计算机编程语言中,反射机制可以用来:
- 获取类型的信息,包括属性、方法
- 动态调用方法
- 动态构造对象
- 从程序集中获得类型
反射的缺点
- 性能:反射可以理解成是一种解释操作,这个过程总是要慢于直接调用的。当然,性能问题的程度是可以控制的,如果程序在很少涉及的地方使用,性能将不会是一个问题。
- 反射模糊了程序内部实际发生的事情,会比直接代码更加复杂。
缺点不能掩饰其优点,针对不同的场景使用合理的技术才是最高境界。
反射的使用场景
- 序列化(Serialization)和数据绑定(Data Binding)
- 远程方法调用(RMI)
- 对象/关系数据映射(O/R mapping)
关于c++的反射
我们知道,Java是原生支持反射机制的,通过Class类可以通过名称获得类对象,进一步操作。Python也支持反射机制,可以通过globals()获取对象map,也可以通过inspect模块,提供了自省的方法。但是C++呢?C++原生不支持反射机制,RTTI(运行时类型识别)也仅仅提供了类型的判断。
开闭原则是设计模式的原则之一,对修改是封闭,对扩展开放。一般来说,需要我们对类进行抽象,针对抽象的类进行编程。许多的设计模式中,为了能够满足这一点,我们常常使用一个配置文件,映射字符串与类型。然后通过反射机制获得字符串对应的对象,然后自动装配已达到易于扩展的目的。
本文主要介绍两个小的场景如何实现C++反射。实际上,C++并不是对反射支持的很好,要支持动态和静态反射,还需要慢慢去寻找,我给出一些资料
C++11 reflection library
RTTR 库
Boost.Mirror 库
Mirror C++ reflection library
本文讨论如何在C++中实现简单的反射。
场景
-
C++序列化,与反序列化。序列化就是将对象编程二进制的形式存储在磁盘上,或者通过网络传输给另一台机器。反序列化就是序列化的逆过程。但是这个逆过程,必须要根据字符串来判断将二进制流转化成什么类型的对象。
-
工厂模式,常常是根据一个字符串来获取想要的对象。但是为了满足开闭原则,我们不能简单的在工厂类中不断的修改生产函数来扩展不同的类型。这个时候,需要利用反射,使用抽象类。
实现
思路是:
- 使用map,映射字符串和生产函数
- 每次构造新类型时,将生产函数注册到map中
- 工厂函数通过map获得生产函数,建造不同的对象
方案一
- map存储在Object抽象父类中
- 使用ClassInfo辅助类型保存子类对象(包括了子类对象的构造函数)
- map映射结构—->子类名称:ClassInfo*
// Reflex.h class Object{ public: Object(){} virtual ~Object(){} static bool Register(ClassInfo *ci); // 注册函数 static Object *CreateObject(string name); } using ObjectConstructorFn = Object *(*)(void); // 构造函数指针 class ClassInfo { public: ClassInfo(const string classname, ObjectConstructorFn ctor) :class_name_(classname), m_object_constructor_(ctor) { Object::Register(this); // 注入到Object中 } virtual ~ClassInfo(){}; Object *CreateObject() const { // 返回当前类型的构造函数 return m_object_constructor_ ? (*m_object_constructor_) : 0; } const string GetClassName() const {return class_name_;} ObjectConstructorFn GetConstructor() {return m_object_constructor_;} private: string class_name_; ObjectConstructorFn m_object_constructor_; // 维护对象信息 } ============================================================== // Reflex.cpp #include "Reflex.h" static unordered_map<string, ClassInfo *> *class_map = nullptr; // 延迟到第一次注册 bool Object::Register(ClassInfo *ci) { if (!class_map) { class_map = new unordered_map<string, ClassInfo *>(); } if (ci) { // 如果没有注册过 string c_name = ci -> GetClassName(); if (class_map -> find(c_name) == class_map -> end()) { class_map[c_name] = ci; } return true; } return false; } Object *Object::CreateObject(string name) { // 如果注册过就直接调用classinfo的createobject if (class_map -> find(name) != class_map.end()) return class_map[name] -> CreateObject(); return nullptr; } ============================================================== // test.cpp class A : public Object { public: A(){} ~A(){} ClassInfo *GetClassInfo const{ return &m_class_info_;} // 自定义生产函数 static Object *CreateObject() { return new A; } protected: static ClassInfo m_class_info_; } // 最重要的一步,将当前类注册到Object中 ClassInfo A::m_class_info_("A", A::CreateObject); int main() { Object *obj = Object::CreateObject("A"); delete obj; return 0; }
上面的代码实现了简单的反射机制,但是还不够好。每次构建类都需要写许多重复性的代码。而C++的宏为我们提供了很好的工具来简化重复性的代码。如下:
// Reflex.h // 向类中添加 class_info 属性以及 CreateObject、GetClassInfo方法 #define DECLEAR_CLASS(name) \ protected: \ static ClassInfo m_class_info_; \ public: ClassInfo *GetClassInfo const; \ static Object *CreateObject(); \ // 实现CreateObject和GetClassInfo两个方法 #define IMPLEMENT_CLASS_COMMON(name, func) \ ClassInfo name::m_class_info_((#name), (ObjectConstructorFn) func); \ ClassInfo *name::GetClassInfo() const \ { return &name::m_class_info_;} // classInfo 属性的初始化 #define IMPLEMENT_CLASS(name) \ IMPLEMENT_CLASS_COMMON(name, name::CreateObject) \ Object* name::CreateObject() \ { return new name;} ============================================================== // test.cpp class B : public Object { DECLEAR_CLASS(B) public: B(){} ~B(){} }; IMPLEMENT_CLASS(B)
方案二
- map存储在单例工厂类中
- 定义RegisterAction类型完成注册动作
- 同样使用宏将重复性的代码简化
//工厂类的定义 class ClassFactory{ private: map<string, PTRCreateObject> m_classMap ; ClassFactory(){}; //构造函数私有化 public: void* getClassByName(string className); void registClass(string name, PTRCreateObject method) ; static ClassFactory& getInstance() ; }; //工厂类的实现 //@brief:获取工厂类的单个实例对象 ClassFactory& ClassFactory::getInstance(){ static ClassFactory sLo_factory; return sLo_factory ; } //@brief:通过类名称字符串获取类的实例 void* ClassFactory::getClassByName(string className){ map<string, PTRCreateObject>::const_iterator iter; iter = m_classMap.find(className) ; if ( iter == m_classMap.end() ) return NULL ; else return iter->second() ; } //@brief:将给定的类名称字符串和对应的创建类对象的函数保存到map中 void ClassFactory::registClass(string name, PTRCreateObject method){ m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ; } //注册动作类 class RegisterAction{ public: RegisterAction(string className,PTRCreateObject ptrCreateFn){ ClassFactory::getInstance().registClass(className,ptrCreateFn); } }; ============================================================== //test class B class TestClassB{ public: void m_print(){ cout<<"hello TestClassB"<<endl; }; }; //@brief:创建类实例的回调函数 TestClassB* createObjTestClassB{ return new TestClassB; } //注册动作类的全局实例 RegisterAction g_creatorRegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB); ============================================================== // 使用宏简化重复性代码 #define REGISTER(className) \ className* objectCreator##className(){ \ return new className; \ } \ RegisterAction g_creatorRegister##className( \ #className,(PTRCreateObject)objectCreator##className)
宏
既然提到了宏,这里简单的复习一下,宏是由 #define 定义而来。在预处理阶段进行宏展开。它的格式是:
#define <宏名> (<参数表>) <宏体>
#define N 2 + 2 // 仅仅是字符串替换 #define N (2 + 2) // 也是字符串 ,但是是(2 + 2) #define area(x) (x) * (x) // 带参的宏定义参会当作字符串直接替换 三种特殊的符号: # #define Conn(x, y) x##y // 表示连接,数字,字符串都可以 ## #define ToString(x) #x // 就是加上双引号 #@ #define ToChar(x) #@x //就是加上单引号, 越界会报错
总结
反射在很多情况下都需要使用,应用场景比较广泛,希望读者能够仔细阅读代码。将反射机制使用在自己的工程里,实现一些设计良好的框架。另外,C++宏的使用可以极大的简化一些重复性的代码,可以仔细研究一下。
=============
来自http://blog.csdn.net/scythe666/article/details/51718864
在 C++ 中实现反射
反射(Reflection)是许多语言(如 C#,Java)都拥有的特性,用于在运行时获取类型信息,大大的提高了编程的灵活性,比如利用反射可以极大的简化 json/xml 解析、脚本绑定、属性编辑器等的实现。但是 C++ 并没有提供反射的支持,本文讨论在 C++ 中实现反射机制的一种方式。
实现原理
在 C# 等语言中,类型信息是在编译时由编译器解析并存储到元数据(Meta Data)中的,其中包括类的名称、方法、属性等信息。每新建立一个类,编译器就会自动生成对应的类型信息,类型信息会被关联在每一个对象上。
但是在 C++ 中,编译器并没有为我们做这样的事情,我们只能自己将这些信息获取并保存下来。我们使用类似下面的结构存储类的相关信息:
// 类信息 class Type { // 类名 std::string name; // 基类 const Type* baseType; // 是否是枚举类型 bool isEnum; // 构造方法 std::vector<const Constructor*> constructors; // 属性 std::unordered_map<std::string, const Field*> fieldsMap; // 方法,由于要支持重载,所以一个方法名对应多个方法 std::unordered_map<std::string, std::vector<const Method*>> methodsMap; };
// 引用类型 enum class ReferType { None, // 无引用类型(值类型) Refer, // 左值引用 RightRefer, // 右值引用 }; // 修饰类型,比如 int*、const Type、float& class QualifiedType { // 基本类型 const Type* type = nullptr; // 是否使用 const 修饰 bool isConst = false; // 是否使用 volatile 修饰 bool isVolatile = false; // 指针层级数量 int pointerCount = 0; // 引用类型 ReferType referType = ReferType::None; }; // 属性 class Field { // 属性名 std::string name; // 所属的类 const Type* ownerType; // 属性类型,注意是修饰类型 const QualifiedType fieldType; // 是否为类属性 bool isStatic; }; // 方法 class Method { // 方法名 std::string name; // 返回类型 const QualifiedType returnType = nullptr; // 所属的类 const Type* ownerType = nullptr; // 参数列表 std::vector<QualifiedType> paramTypes; // 是否为类方法 bool isStatic; };
通过在类声明中插入代码来注册类型信息,并大量使用模板和宏来简化代码,以 Constructor 为例,其实现如下:
template<class T, class... Args> class ConstructorImpl : public Constructor { private: const Type* type; public: ConstructorImpl() : Constructor(typeof(T), { GetQualifiedType<Args>::Value() ... }) { static_assert(std::is_constructible<T, Args...>::value, "tried to register an undeclared constructor"); } virtual Any Invoke(typename AsType<Args, Any>::Value... params) const override { return (Any)new T(std::forward<Args>((Args)params)...); } };
注册方法信息的实现类似这样:
template<class OwnerType, class ReturnType, class... Args> const Method* make_method(const std::string& name, ReturnType(OwnerType::*fun)(Args...)){ return new MemberMethod<OwnerType, ReturnType, Args...>(name.substr(name.find_last_of(':') + 1), fun); } #define METHOD(fun) make_method(#fun, fun)
使用示例
下面演示了反射的枚举定义,和反射类型信息的描述
REFLECT_ENUM(Sex, Male, Female) class PhoneNumber{ BEGIN_TYPE(PhoneNumber) FIELDS(FIELD(&PhoneNumber::areaCode), FIELD(&PhoneNumber::number)) CTORS(DEFAULT_CTOR(PhoneNumber), CTOR(PhoneNumber, const std::string&, const std::string&)) METHODS(METHOD(&PhoneNumber::ToString)) END_TYPE public: std::string areaCode; std::string number; PhoneNumber() {} PhoneNumber(const std::string& areaCode, const std::string& number) : areaCode(areaCode), number(number) {} std::string ToString() const { return areaCode + " " + number; } }; class Person{ BEGIN_TYPE(Person) FIELDS(FIELD(&Person::name), FIELD(&Person::sex), FIELD(&Person::phoneNumber), FIELD(&Person::totalNumber)) CTORS(DEFAULT_CTOR(Person), CTOR(Person, const std::string&, float, Sex)) METHODS(METHOD(&Person::Name), METHOD(&Person::GetSex), METHOD(&Person::GetPhoneNumber), METHOD(&Person::SetPhoneNumber), METHOD(&Person::GetTotalNumber)) END_TYPE protected: std::string name; Sex sex; PhoneNumber phoneNumber; static int instanceCount; public: Person() { totalNumber++; } std::string& Name() { return name; } Sex GetSex() const { return sex; } const PhoneNumber& GetPhoneNumber() { return phoneNumber; } void SetPhoneNumber(const PhoneNumber& phoneNumber) { this->phoneNumber = phoneNumber; } static int GetInstanceCount() { return instanceCount; } }; int Person::instanceCount = 0;
然后可以像下面这样使用
// 利用反射可以实现通用的 json/xml 转换 auto p = JsonParser::Parse<Person>(R"( { "name": "John", "sex": "Female", "phoneNumber": { "areaCode": "+86", "number": "13888888888" } } )"); // 通过反射调用构造方法 auto newPhone = Type::GetType("PhoneNumber")->GetConstructor({qualified_typeof(const std::string&), qualified_typeof(const std::string&)})->Invoke(std::string("+86"), std::string("13000000000")); // 调用带参数的方法 p->GetType()->GetMethod("SetPhoneNumber")->Invoke(p.get(), newPhone); // 调用类方法 int instanceCount = typeof(Person)->GetMethod("GetInstanceCount")->Invoke(nullptr); // 获取属性值 Sex sex = p->GetType()->GetField("sex")->Get(p.get()); // 获取枚举值的名字 std::cout << Enum::GetName(sex) << std::endl; // 输出所有属性的名字 for (auto f : typeof(Person)->GetFields()){ std::cout << f->GetName() << "," << std::endl; }
不足之处
- 由于大量使用模版技术,会导致代码膨胀
- 侵入式的声明方式,必须对现有代码做改动才能使用,如果不需要运行时类型信息,可以改进成在一个单独的初始化方法里进行注册
Demo 地址
Github: https://github.com/Sleen/cpp_reflection