C++反射的实现
来源:互联网 发布:西游之路法宝进阶数据 编辑:程序博客网 时间:2024/06/07 03:11
前言
反射的概念:
指程序在运行时,访问、检测和修改它本身状态或行为的一种能力。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.cppclass 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.cppclass 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 Bclass 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++宏的使用可以极大的简化一些重复性的代码,可以仔细研究一下。
- Objective-C中关于类反射的实现
- [C#] 反射的用法
- Objective-C的反射
- Objective-C的反射
- Objective-C的反射
- 反射机制的实现
- 实现C++的反射
- Java反射的实现
- 反射的实现原理
- C++反射的实现
- C++反射的实现
- RunTime实现的反射
- C++反射的实现
- C++ 反射的实现
- 安卓so动态库加载代理实现,可以实现C层的类反射效果
- objective c实现配置文件+反射 工厂创建
- c 结构体反射机制实现
- linux下实现C语言反射
- spring cloud Hystrix
- Oracle查询每一个用户的最后一个登录时间
- 初中OI打味极鲜记 (掺杂大量无关内容)
- php 解决json_encode中文UNICODE转码问题
- //图片预览
- C++反射的实现
- Codeforces 567E President and Roads 题解
- C++二维数组作为函数参数传递
- 三个例子,搞懂java中的main参数String[] args
- 23个设计模式
- java语言基础
- C++ 预处理、编译、汇编、链接
- JavaScript 相等(==)与全等(===)操作符
- python统计考试成绩代码参考