`
modabobo
  • 浏览: 508317 次
文章分类
社区版块
存档分类
最新评论

C++反射机制的实现

 
阅读更多

前几天用C++为《捕鱼达人》移植UI编辑器的时候,遇到了几个难点。一个是通过类名的字符串创建相应的类的实例化。还有一个是通过属性的名字字符串来操作相应的类的属性。用支持反射的Objective-C或者Java语言来实现类似功能是非常简单的。但是C++不支持,纠结了几天,终于实现了类似于反射的功能。

思路分为以下几步:

1、在要反射的类中定义一个回调函数,用来创建这个类的实例;

2、设计一个工厂类,类中有一个std::map,用于保存类名和创建实例的回调函数。通过类工厂来动态创建类对象;

3、程序开始运行时,将回调函数存入std::map(哈希表)里面,类名字做为map的key值;

下面我来一步一步的讲解具体的实现方法。

首先声明一个回调函数

typedef void* (*createClass)(void) ;

定义一个工厂类

class CKClassFactory
{
public:
    CKClassFactory() ;
 
    virtual ~CKClassFactory() ;
 
    void* getClassByName(string className) ;
 
    void registClass(string name, createClass method) ;
 
    static CKClassFactory& sharedClassFactory() ;
 
private:
    map<string, createClass> m_classMap ;
} ;


这里把工厂类设计成单件类,通过静态函数sharedClassFactory()来调用类中方法,静态类实例保证了类在开始运行前就存在。

m_classMap用来保存回调函数指针,通过registClass()函数来实现类名和函数的插入。

getClassByName()函数返回map中通过回调函数创建的类的实例化,参数为传入的类名。

下面是实现方法。

void* CKClassFactory::getClassByName(string className)
{
    map<string, createClass>::const_iterator iter ;
 
    iter = m_classMap.find(className) ;
    if ( iter == m_classMap.end() )
        return NULL ;
    else
        return iter->second() ;
}
 
void CKClassFactory::registClass(string name, createClass method)
{
    m_classMap.insert(pair<string, createClass>(name, method)) ;
}
 
CKClassFactory& CKClassFactory::sharedClassFactory()
{
    static CKClassFactory _sharedClassFactory ;
    return _sharedClassFactory ;
}


这样,我们的单件工厂类就设计完成了。

下面我们需要设计一个用来动态创建类的类,被创建的类通过本类的一个静态对象来向类工厂注册对象创建的函数。

class CKDynamicClass
{
public:
    CKDynamicClass(string name, createClass method)
    {
        CKClassFactory::sharedClassFactory().registClass(name, method) ;
    }
} ;
 
#define DECLARE_CLASS(className)\
string className##Name ;        \
static CKDynamicClass* m_className##dc ;
 
#define IMPLEMENT_CLASS(className)  \
CKDynamicClass* className::m_className##dc = \
new CKDynamicClass(#className, className::createInstance) ;



该类设计了两个宏,用于实现动态创建,后面的类中会用到。

下面来设计一个基类,所有动态创建的类是继承于该类的。

该类主要为了实现两个功能,一个是配合类工厂来创建一个新的子类,一个是通过map来动态创建类的属性,动态创建属性类似于上面的动态创建类。

下面先帖代码:

typedef void (*setValue)(CKBaseClass *t, void* c) ;
 
class CKBaseClass
{
private:
    DECLARE_CLASS(CKBaseClass)
 
public:
    CKBaseClass() {}
    virtual ~CKBaseClass() {}
    static void* createInstance() {return new CKBaseClass();}
    virtual void registProperty() {}
    virtual void display() {}
    map<string, setValue> m_propertyMap ;
} ;
 
#define SYNTHESIZE(classType, varType, varName)    \
public:                                             \
inline static void set##varName(CKBaseClass*cp, void*value){ \
    classType* tp = (classType*)cp ;                        \
    tp->varName = (varType)value ;                      \
}                                                       \
inline varType get##varName(void) const {                \
    return varName ;                                      \
}
 IMPLEMENT_CLASS(CKBaseClass)


先有一个函数指针,用来动态创建属性并赋值。函数指针插入到m_propertyMap里面,key值为函数的名字。

createInstance函数返回了本类的实例化,通过DECLARE_CLASS宏,声明了一个字符串和一个静态的CKDynamicClass类指针,类的外面通过IMPLEMENT_CLASS宏对CKDynamicClass类指针进行初始化,这里通过在构造传入的类名和createInstance函数),来将对应的函数插入到类工厂的map里面。

到这一步,类反射的功能即将要实现了,喝口水,歇下接着写。

类里面还有两个东东没有介绍,registProperty函数,用来注册创建属性的函数指针,类似于创建类,将对应的函数插入到map里面。display函数用来后面做测试。

下面我们来设计最后一个类,就是将要被动态创建的类,先帖码。

public:
    SYNTHESIZE(CKHelloClass, int*, m_pValue)
 
    CKHelloClass() {}
    virtual ~CKHelloClass(){}
    static void* createInstance()
    {
    	return new CKHelloClass() ;
    }
    virtual void registProperty()
    {
    	m_propertyMap.inset(pair<string, setValue>("setm_pValue", setm_pValue)) ;
    }
    virtual void display()
    {
    	cout << *getm_pValue() << endl ;
    }
protected:
    int *m_pValue ;
 
} ;
IMPLEMENT_CLASS(CKHelloClass)


CKHelloClass类是我们要动态创建出来的类,继承于CKBaseClass。

DECLARE_CLASS的宏是必须要实现的,声明了一个字符串和一个静态的CKDynamicClass类指针,类的外面通过IMPLEMENT_CLASS宏对CKDynamicClass类指针进行初始化。

SYNTHESIZE宏,用来给m_pValue来实现Set和Get方法。

createInstance函数返回本类的实例化。

registProperty函数来将Set函数插入到map中。

display函数用来测试m_pValue指针是否赋值成功。

最后一步,在main函数中来实现。

CKBaseClass *pVar = (CKBaseClass*)CKClassFactory::sharedClassFactory().getClassByName("CKHelloClass") ;
    pVar->registProperty() ;
 
    int pValue = 123456 ;
 
    pVar->m_propertyMap["setm_pValue"](pVar, &pValue) ;
    pVar->display() ;


声明一个基类的指针,通过CKClassFactory的getClassByName来返回一个CKHelloClass的实例化赋值给该指针pVar。

pVar调用registProperty函数来注册属性,属性的Set函数被插入到CKHelloClass的m_propertyMap里面。

我们来做下测试,声明一个变量pValue并赋值,然后传入m_proeprtyMap里面,key值为CKHelloClass中的Set函数。这样,Set函数会被相应调用,然后将pValue的指针赋值给相应的CKHelloClass成员指针m_pValue,同过display函数调用,成功的打印出m_pValue指针的值。

到此,C++反射的实现讲解完成,这类实现方法适合在开发各类的编辑器中去使用,包括微软的MFC等等。在开发编辑器的阶段,并没有相应的类,但是使用者想通过在编辑器中传入类的名字,然后在开发中,根据编辑器传入的类名,新建一个类去实现的话,这种方法非常适用,更多的用法等待大家去发掘。

最后放上本文章的源代码,XCode工程,使用GCC4.2编译器。代码中用到了标准C++库STL,稍微修改工程,即可实现多平台编译。

C++反射源代码

谢谢大家。

分享到:
评论

相关推荐

    C++反射机制实现

    C++反射机制实现,根据类名字符串创建该类的实例;根据类的属性字符串来设置属性;

    C++反射机制

    C++反射机制

    C++实现反射机制

    C++实现反射机制

    c++反射 类序列化为json

    c++ 的反射 RTTR实现

    CLI/C++反射机制交互C#、C++

    .Net 环境下C# 通过托管C++调用本地C++ Dll文件,其中CLI/C++工程里的主类实现了C#写好的接口,C#使用反射机制实现C++的方法集,非常经典的例子,与大家分享

    Qt 反射机制实现,通过类名创建对象

    反射是指程序在运行时动态获取对象属性与...简单一点说,就是可以通过类名称来创建一个类对象,这在Java和Object-C中是原生支持的,所以实现起来非常简单,但是C++就不支持了,如果想要用到反射机制,那就得自己实现。

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

    C++ 反射机制 一.前言: Java有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的...

    c++坦克大战、反射机制实现等

    全部源码均由自己编写测试,想学习c++的朋友可下载学习研究,对于所有文件均打包处理。

    C++模拟实现反射的代码和代码解析文章

    很久前弄了一个,最近应用了typelist技术改写了,顺便把blog上1年多前许愿要写一个相关文章的坑填了。

    利用C++ ATL技术实现反射机制

    然后描述了ATL动态链接库实现反射机制的基本原理,完善了ATL IDL文件接口标识符定义,利用前绑定或后绑定技术实现反射机制,比较了这两种方法的不同之处,着重强调了Idispatch接口在实现反射机制中的作用,最后给出...

    reflection:利用模板建立C++的反射机制。还有待完善

    也是我比较满意的一个C++反射系统实现code,利用大量的bookkeeping和模版方法。其中,用于实现这一技术最关键的RSC工具还没完成。有时间了就会赶的。#开发环境平台:Windows 8.1IDE:VS 2015 preview

    用C++来实现类Unity3d的AddComponent

    用C++来实现类Unity3d的AddComponent 如何使用类名来创建类实例。

    C# 使用反射来实现对象的深度复制方法

    所以使用反射机制来实现。   但是如果是服务端运行的话,还是建议手动的实现。 毕竟反射机制比直接写出来的效率要慢一些。 代码: public static class DeepCopyHelper { public static object Copy(this object...

    C++反射的一种实现方法详解

    ...create_object:从RegistryMap里找到传入name对应的RegistryNode(RegistryNode保存了名字和构造函数),调用构造函数返回。 register_class:用传入的name和constructor注册RegistryMap,只在Register的构造函数里面...

    Java学习之反射机制

    虽然在这样的定义下java不是动态语言,但java的反射机制(Reflection)却是可实现动态的相关机制。java反射机制的作用有  1、在运行时判断任意一个类所具有的成员变量和方法  2、在运行时构造任意一个类的对象 ...

    WorkFlow.7z

    QT/C++实现的反射机制,通过字符串创建三个线程执行

Global site tag (gtag.js) - Google Analytics