全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

C++ 反射机制详解及实例代码

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++反射机制的实现就大功告成了!。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# C++  # 反射机制  # 反射机制详解及实例  # 在C++中反射调用.NET的方法(一)  # 在C++中反射调用.NET的方法(二)  # 在C++中反射调用.NET的方法(三)  # C++反射的一种实现方法详解  # 就可以  # 只需  # 我们可以  # 大功告成  # 要让  # 可以实现  # 来实现  # 回调  # 自己的  # 都是  # 实现了  # 加载  # 几个  # 序列化  # 有个  # 都要  # 也就  # 中有  # 要在  # 很容易 


相关文章: 如何用腾讯建站主机快速创建免费网站?  道歉网站制作流程,世纪佳缘致歉小吴事件,相亲网站身份信息伪造该如何稽查?  建站之星安装模板失败:服务器环境不兼容?  网站建设设计制作营销公司南阳,如何策划设计和建设网站?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?  如何快速搭建自助建站会员专属系统?  模具网站制作流程,如何找模具客户?  建站之星代理如何优化在线客服效率?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  建站之星如何快速生成多端适配网站?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  建站主机CVM配置优化、SEO策略与性能提升指南  如何选择CMS系统实现快速建站与SEO优化?  建站主机选购指南:核心配置与性价比推荐解析  如何在IIS中新建站点并解决端口绑定冲突?  音响网站制作视频教程,隆霸音响官方网站?  上海网站制作网页,上海本地的生活网站有哪些?最好包括生活的各个方面的?  如何高效利用亚马逊云主机搭建企业网站?  如何在宝塔面板中创建新站点?  如何在云主机快速搭建网站站点?  网站按钮制作软件,如何实现网页中按钮的自动点击?  如何通过云梦建站系统实现SEO快速优化?  如何高效利用200m空间完成建站?  高端网站建设与定制开发一站式解决方案 中企动力  建站主机是什么?如何选择适合的建站主机?  JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)  PHP 500报错的快速解决方法  如何通过FTP空间快速搭建安全高效网站?  如何选择域名并搭建高效网站?  如何制作一个表白网站视频,关于勇敢表白的小标题?  如何规划企业建站流程的关键步骤?  如何选择可靠的免备案建站服务器?  子杰智能建站系统|零代码开发与AI生成SEO优化指南  如何生成腾讯云建站专用兑换码?  一键网站制作软件,义乌购一件代发流程?  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  建站之星后台管理如何实现高效配置?  h5在线制作网站电脑版下载,h5网页制作软件?  大连网站制作公司哪家好一点,大连买房网站哪个好?  安云自助建站系统如何快速提升SEO排名?  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  如何在IIS中配置站点IP、端口及主机头?  大学网站设计制作软件有哪些,如何将网站制作成自己app?  制作门户网站的参考文献在哪,小说网站怎么建立?  正规网站制作公司有哪些,目前国内哪家网页网站制作设计公司比较专业靠谱?口碑好?  建站之星官网登录失败?如何快速解决?  购物网站制作公司有哪些,哪个购物网站比较好?  北京营销型网站制作公司,可以用python做一个营销推广网站吗?  建站DNS解析失败?如何正确配置域名服务器? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。