版权声明:本文为CSDN博主「YzlCoder」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/y1196645376/article/details/51455273

前言

JAVA有着一个非常突出的动态相关机制Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。然而C++不支持反射机制,虽然C++有RTTI(运行时类型识别)。但是想要实现C++对象序列化,序列化就是存储到磁盘上,将对象变成一定格式的二进制编码,然后要用的时候再将保存在磁盘上的二进制编码转化成一个内存中的对象,这个过程中总是需要有一个指示来告诉编译器要生成什么样的对象,最简单的方式当然就是类名了,例如:将一个ClassXXX对象存储到磁盘上,再从磁盘读取的时候让编译器根据“ClassXXX”名称来new一个对象。

ClassT* obj = FactoryCreate("ClassT");

类似于以上的语法,虽然C++没有自带的语法可以实现,但是我们可以自己通过其他方法来实现。

实现:

简单工厂模式

我们很容易可以想到可以使用简单工厂模式来实现这个效果:比如

// 这个是所有需要实现反射机制的类需要继承的基类,然后派生出来的类只需要再实现这个ToString即可。
class Object
{public:virtual string ToString() = 0;
};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都要进行修改。十分不利于维护。所以我们需要换一个方式来处理。

工厂模式+回调机制

首先我们要梳理一下这个方法的基本脉络:

  1. 工厂内部需要有个映射,也就是一个字符串对应一个类new的方法。
  2. 工厂给出一个接口,我们传入字符串,那么返回这个字符串对应的方法new出来的对象指针。
  3. 我们新建的类,如果需要支持反射机制,那么这个类需要自动将自己的new方法和名字注册到工厂的映射中。

OK,如果我们能完成以上几个要求,那么我们在类进行拓展的时候需要改动的地方就十分少了。对于工厂的代码我们基本上是不会改变的。也就基本上实现了我们C++反射机制的基本功能。

下面我们来一步一步解析代码:

首先我们还是需要一个Object作为需要支持反射机制类的基类

//Reflex.h
class Object
{public:Object() {}virtual ~Object() {}public:static bool Register(ClassInfo* pClassInfo); // 注册传入一个classInfo(类信息),将这个类的信息注册到映射中static Object* CreateObject(const std::string& className); // 工厂生产对象的接口
};

然后是实现:

//Reflex.cpp
std::map<string, ClassInfo*> gClassInfoMap;bool Object::Register(ClassInfo* pClassInfo)
{if (nullptr == pClassInfo) return false;std::string className = pClassInfo->GetClassName();if (gClassInfoMap.find(className) != gClassInfoMap.end()) return false;gClassInfoMap.insert({className, pClassInfo }); // 类名 <-> classInforeturn true;
}Object* Object::CreateObject(const std::string& className)
{auto iter = gClassInfoMap.find(className);if (iter == gClassInfoMap.end())return nullptr;return iter->second->CreateObject();         //当传入字符串name后,通过name找到info,然后调用对应的CreatObject()即可
}

剩下的我们还需要一个classinfo类就大功告成了:

//Reflex.h
typedef Object*(*ConstructorFunc)(void);class ClassInfo
{public:ClassInfo(const std::string className, ConstructorFunc ctor):m_className(className), m_objectConstructor(ctor){Object::Register(this); // classInfo的构造函数是传入类名和类对应的new函数然后自动注册进map中}~ClassInfo() {}public:std::string GetClassName() { return m_className; }public:Object* CreateObject() { return (*m_objectConstructor)(); }private:string m_className;ConstructorFunc m_objectConstructor;
};

有了这些类后,我们只需要让需要支持反射的类满足以下要求即可:

  1. 继承Object类。
  2. 重载一个CreatObject()函数,里面 return new 自身类。
  3. 拥有一个classInfo的成员并且用类名和CreatObject初始化。

满足以上三个要求的类我们就可以利用反射机制来创建对象了。我们可以看下面的例子:

class DerivedObject : public Object
{public:DerivedObject () {}~DerivedObject () { }public:static Object* CreateObject() { return new DerivedObject; }protected:static ClassInfo ms_classinfo;
};ClassInfo DerivedObject ::ms_classinfo("DerivedObject", DerivedObject ::CreateObject);

使用的话我们就只需要调用Object::CreatObject(const std::string& className)传入类名即可。

int main()
{Object* obj = Object::CreateObject("DerivedObject");delete obj;return 0;
}

基本上反射机制的功能就实现了,而且使用回调注册在后期拓展上也容易维护。

使用宏简化代码:

其实大家发现,因为我们要让类支持反射那么就要满足我们上面的那三个要求,但是每个类都要写这样相似的东西。仔细一看,包括函数申da’s明、函数定义、函数注册,每个类的代码除了类名外其它都是一模一样的,有没有简单的方法呢?
那就是使用宏。

//Reflex.h#define DECLARE_CREATEOBJECT(CLASS_NAME) \public:\static Object* CreateObject() { return new CLASS_NAME; }#define DECLEAR_CLASSINFO \protected:\static ClassInfo ms_classinfo;#define INIT_CLASS_INFO(CLASS_NAME) \ClassInfo CLASS_NAME::ms_classinfo(#CLASS_NAME, CLASS_NAME::CreateObject);

有了宏替换后,我们定义一个新的类。例如我们上面的类B就可以这样写:

class DerivedObject : public Object
{public:DerivedObject() {}~DerivedObject() { }DECLARE_CREATEOBJECT(DerivedObject)
DECLEAR_CLASSINFO
};INIT_CLASS_INFO(DerivedObject)

这样不管以后需要添加、修改什么功能都只需要修改宏就可以了而不需要每个类每个类去添加、修改方法。

ok到这里基本上,c++反射机制的实现就大功告成了!。

C++ 实现反射机制(转载)相关推荐

  1. Java的反射机制 工厂模式综合讲解【转载自51CTO】

    2019独角兽企业重金招聘Python工程师标准>>> Java的反射机制 工厂模式综合讲解 1.什么叫反射 Java.lang.reflect包下 正常情况下我们可以通过类实例化一 ...

  2. (转载)Java反射机制

    Java反射机制是Java语言被视为准动态语言的关键性质.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调 ...

  3. Golang反射机制的实现分析——reflect.Type方法查找和调用

    在<Golang反射机制的实现分析--reflect.Type类型名称>一文中,我们分析了Golang获取类型基本信息的流程.本文将基于上述知识和经验,分析方法的查找和调用.(转载请指明出 ...

  4. Golang反射机制的实现分析——reflect.Type类型名称

    现在越来越多的java.php或者python程序员转向了Golang.其中一个比较重要的原因是,它和C/C++一样,可以编译成机器码运行,这保证了执行的效率.在上述解释型语言中,它们都支持了&quo ...

  5. 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换

    作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...

  6. 【教程】【FLEX】#004 反射机制

    总结: 目前用到反射的主要有两个方法 1.  getDefinitionByName    //根据类名,返回对象(反射实例化对象) 2.  describeType                 ...

  7. Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法...

    Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法 www.MyException.Cn   发布于:2012-09-15 ...

  8. 利用Java反射机制和poi插件操作excel

    最近在公司写一个利用poi插件读取excel的东西,,不想每一个都写一遍解析代码.就想利用Java的反射机制,写对应的实体类,获取对应excel中的值,下面是解析的代码,仅供参考.不足之处,望指出/* ...

  9. Java反射机制分析指南

    一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...

  10. 反射 字段_详解面试中常考的 Java 反射机制

    反射(Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性和方法. 反射是一项高级 ...

最新文章

  1. python中set怎么循环_python如何遍历set
  2. 物理化学 热力学第一定律的概念
  3. OpenCV在图像上添加边框borders
  4. HTML5+CSS3构建同页面表单间的动画切换
  5. 【渝粤题库】陕西师范大学500013 物理教学论 作业(专升本)
  6. C++学习之路 | PTA(天梯赛)—— L2-007 家庭房产 (25分)(带注释)(并查集)(精简)
  7. python读取两个csv文件后比较_python – 读取两个csv文件并比较每一行.如果行匹配打印两行,如果不相似则打印无效...
  8. vue-cli 引用elementUI打包后文件过大
  9. 生物力学有限元Mimics/ANSYS
  10. C++ fork函数理解
  11. cad字体安装_CAD字体大全下载【软件下载】
  12. 学生成绩预测模型_学生成绩分析预测
  13. 硬件之OC、OD、推挽解释
  14. python字符串格式化是什么意思_Python字符串格式化中%s和%d之间有什么区别?...
  15. PS 如何去除光晕的黑色背景
  16. 企业信息化整体架构图
  17. Ubuntu22.04 用 `hwclock` 或 `timedatectl` 来设置RTC硬件时钟为本地时区
  18. java实训感想6000字_JAVA论文6000字:无线校园
  19. 二分查找、快速排序对比和详解
  20. 事无巨细,时钟芯片DS1302

热门文章

  1. 第 25 章 Build tool
  2. 在win7物理机,使用vmware,3台centos7系统,分别部署httpd,php-fpm,mariadb
  3. [20171120]11G关闭直接路径读.txt
  4. AI与大众最近的接触——智能语音交互
  5. mysql cluster安装报错
  6. Apache Drill
  7. Wireshark 常用过滤
  8. Hibernate深入浅出(六)事务2——锁locking
  9. C++笔试题 String类的实现 三大复制控制函数
  10. P2P端口映射 UPnP功能和使用详解