C++ 反射机制
一.前言:
Java有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。然而C++是不支持反射机制,虽然C++有RTTI(运行时类型识别)。但是想要实现C++对象序列化,序列化就是存储到磁盘上,将对象变成一定格式的二进制编码,然后要用的时候再将保存在磁盘上的二进制编码转化成一个内存中的对象,这个过程中总是需要有一个指示来告诉编译器要生成什么样的对象,最简单的方式当然就是类名了,例如:将一个ClassXXX对象存储到磁盘上,再从磁盘读取的时候让编译器根据“ClassXXX”名称来new一个对象。
ClassT* obj = FactoryCreate("ClassT");
类似于以上的语法,虽然C++没有自带的语法可以实现,但是我们可以自己通过其他方法来实现。(由于本人能力有限,所以该篇博客只是讲解如何简单的实现这个反射机制,而对C++中拥有这个反射机制是否有必要不做任何讨论。当然,如果博客中有什么地方说的有错误还望大家可以在下面评论指出谢谢)
二.实现:
1.我们很容易可以想到可以使用简单工厂模式来实现这个效果:比如
class Object { public: virtual string ToString() = 0; };
这个是所有需要实现反射机制的类需要继承的基类,然后派生出来的类只需要再实现这个ToString即可。例如:
class MyClass :public Object { public: virtual string ToString(){ return "MyClass"; } };
然后就是用于产生对象的工厂。
Object* FactoryCreat(const string& className) { if (className == "ClassA") return new ClassA; else if (className == "ClassB") return new ClassB; else if(className == "ClassC") return new ClassC; else if(className == "ClassD") return new ClassD; else if(className == "ClassE") return new ClassE; ... }
我们使用就可以这样:
int main() { Object* obj = FactoryCreat("MyClass"); cout << obj->ToString(); delete obj; return 0; }
我们使用简单工厂模式感觉好像是解决了问题,可以实现用字符串去new一个对应的对象,但是假如我们要新建一个类或者修改一个类,那么这个FactoryCreat都要进行修改。十分不利于维护。所以我们需要换一个方式来处理。
2.工厂模式结合回调机制。
首先我们要梳理一下这个方法的基本脉络:
1.工厂内部需要有个映射,也就是一个字符串对应一个类new的方法。
2.工厂给出一个接口,我们传入字符串,那么返回这个字符串对应的方法new出来的对象指针。
3.我们新建的类,如果需要支持反射机制,那么这个类需要自动将自己的new方法和名字注册到工厂的映射中。
OK,如果我们能完成以上几个要求,那么我们在类进行拓展的时候需要改动的地方就十分少了。对于工厂的代码我们基本上是不会改变的。也就基本上实现了我们C++反射机制的基本功能。
下面我们来一步一步解析代码:
首先我们还是需要一个Object作为需要支持反射机制类的基类
//Reflex.h class Object { public: Object(){} virtual ~Object(){} static bool Register(ClassInfo* ci); //注册传入一个classInfo(类信息),将这个类的信息注册到映射中 static Object* CreateObject(string name); //工厂生产对象的接口 };
然后是实现:
//Reflex.cpp static std::map< string, ClassInfo*> *classInfoMap = NULL; bool Object::Register(ClassInfo* ci) { if (!classInfoMap) { classInfoMap = new std::map< string, ClassInfo*>(); //这里我们是通过map来存储这个映射的。 } if (ci) { if (classInfoMap->find(ci->m_className) == classInfoMap->end()){ classInfoMap->insert(std::map< string, ClassInfo*>::value_type(ci->m_className, ci)); // 类名 <-> classInfo } } return true; } Object* Object::CreateObject(std::string name) { std::map< string, ClassInfo*>::const_iterator iter = classInfoMap->find(name); if (classInfoMap->end() != iter) { return iter->second->CreateObject(); //当传入字符串name后,通过name找到info,然后调用对应的CreatObject()即可 } return NULL; }
剩下的我们还需要一个classinfo类就大功告成了:
//Reflex.h typedef Object* (*ObjectConstructorFn)(void); class ClassInfo { public: ClassInfo(const std::string className, ObjectConstructorFn ctor) :m_className(className), m_objectConstructor(ctor) { Object::Register(this); //classInfo的构造函数是传入类名和类对应的new函数然后自动注册进map中。 } virtual ~ClassInfo(){} Object* CreateObject()const { return m_objectConstructor ? (*m_objectConstructor)() : 0; } bool IsDynamic()const { return NULL != m_objectConstructor; } const std::string GetClassName()const { return m_className; } ObjectConstructorFn GetConstructor()const{ return m_objectConstructor; } public: string m_className; ObjectConstructorFn m_objectConstructor; };
有了这些类后,我们只需要让需要支持反射的类满足以下要求即可:
1.继承Object类。
2.重载一个CreatObject()函数,里面 return new 自身类。
3.拥有一个classInfo的成员并且用类名和CreatObject初始化。
满足以上三个要求的类我们就可以利用反射机制来创建对象了。我们可以看下面的例子:
class B : public Object { public: B(){ cout << hex << (long)this << " B constructor!" << endl; } ~B(){ cout << hex << (long)this << " B destructor!" << endl; } virtual ClassInfo* GetClassInfo() const{ return &ms_classinfo; } static Object* CreateObject() { return new B; } protected: static ClassInfo ms_classinfo; }; ClassInfo B::ms_classinfo("B", B::CreateObject);
使用的话我们就只需要调用Object::CreatObject(string) 传入类名即可。
int main() { Object* obj = Object::CreateObject("B"); delete obj; return 0; }
基本上反射机制的功能就实现了,而且使用回调注册在后期拓展上也容易维护。
三.使用宏简化代码:
其实大家发现,因为我们要让类支持反射那么就要满足我们上面的那三个要求,但是每个类都要写这样相似的东西。仔细一看,包括函数申da's明、函数定义、函数注册,每个类的代码除了类名外其它都是一模一样的,有没有简单的方法呢?
那就是使用宏。
//Reflex.h //类申明中添加 classInfo 属性 和 CreatObject、GetClassInfo 方法 #define DECLARE_CLASS(name) \ protected: \ static ClassInfo ms_classinfo; \ public: \ virtual ClassInfo* GetClassInfo() const; \ static Object* CreateObject(); //实现CreatObject 和 GetClassInfo 的两个方法 #define IMPLEMENT_CLASS_COMMON(name,func) \ ClassInfo name::ms_classinfo((#name), \ (ObjectConstructorFn) func); \ \ ClassInfo *name::GetClassInfo() const \ {return &name::ms_classinfo;} //classInfo 属性的初始化 #define IMPLEMENT_CLASS(name) \ IMPLEMENT_CLASS_COMMON(name,name::CreateObject) \ Object* name::CreateObject() \ { return new name;}
有了宏替换后,我们定义一个新的类。
只需要在类定义中添加 DECLARE_CLASS(classname) 实现中添加IMPLEMENT_CLASS(classname)就可以让这个类实现反射了。
例如我们上面的类B就可以这样写:
class B : public Object { DECLARE_CLASS(B) public: B(){ cout << hex << (long)this << " B constructor!" << endl; } ~B(){ cout << hex << (long)this << " B destructor!" << endl; } }; IMPLEMENT_CLASS(B)
这样不管以后需要添加、修改什么功能都只需要修改宏就可以了而不需要每个类每个类去添加、修改方法。
ok到这里基本上,c++反射机制的实现就大功告成了!。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
本文向大家介绍Java 反射机制详解及实例代码,包括了Java 反射机制详解及实例代码的使用技巧和注意事项,需要的朋友参考一下 Java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解。 下面开始正文。 【案例1】通过一个对象获得完整的包名和类名 【运行结果】:Reflect.D
本文向大家介绍JAVA反射机制实例详解,包括了JAVA反射机制实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例分析了JAVA反射机制。分享给大家供大家参考,具体如下: 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一、先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力
本文向大家介绍PHP的反射机制实例详解,包括了PHP的反射机制实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP的反射机制。分享给大家供大家参考,具体如下: 介绍: PHP5添加了一项新的功能:Reflection。这个功能使得phper可以reverse-engineer class, interface,function,method and extension。通过PHP
本文向大家介绍Java 反射机制的实例详解,包括了Java 反射机制的实例详解的使用技巧和注意事项,需要的朋友参考一下 Java 反射机制的实例详解 前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来。那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现。 正文 Java反射机制定义 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类
本文向大家介绍Linux INotif机制详解及实例代码,包括了Linux INotif机制详解及实例代码的使用技巧和注意事项,需要的朋友参考一下 Linux INotif机制 一、 前言: 众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够
本文向大家介绍php 的反射详解及示例代码,包括了php 的反射详解及示例代码的使用技巧和注意事项,需要的朋友参考一下 最近在看java编程思想,看到类型信息这一章,讲到了类的信息以及反射的概念。顺便温故一下php的反射东西。手册是这样说的:"PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释