天天看点

在C++实现反射

反射这个特性在C++中是没有的。所谓反射,自己的认为就是通过一个名字就可创建、调用、获取信息等一系列的操作,这个在脚本语言里面是比较常见的,COM组件也类似,知道个ID名,就可以做很多的工作了。

看看JAVA中的描述:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为JAVA语言的反射机制。

JAVA反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

反射发挥威力的场所:1.序列化(Serialization)和数据绑定(Data Binding)。2.远程方法调用(Remote Method Invocation RMI)。3.对象/关系数据映射(E/R Mapping)。

虽然没有,但既然我们用的是C++,总是会有办法的~~

ITEM1:动态创建

在实现反射的过程中的第一步要做的可能就是动态创建了,就是用一个类的名字就可以得到这个类的创建函数,从而进行对象的创建。要实现这些,首先对于要反射的类得提供一个能创建自己的回调函数,我们可以使用这个函数来创建这个类的对象,这样,也使得创建活动内聚,减少将来不必要的修改。同时,为了我们可以通过类名获取刚才所说的回调函数,我们就需要一种全局储存结构来保存创建函数和对应类名的映射关系。

这个回调函数就可以是这样的:

static CBaseClass* ClassName::CreateClassName (){

              return new ClassName;

};

在MFC中,我们常使用DECLARE_DYNCREATE宏,这个宏可以使每个CObject的派生类的对象具有运行时动态创建的能力。那么我们也可以使用宏来简化上面实现函数的方法,如下:

#define DEFINE_DYN _CREATE(class_name) /

static CBaseClass * CreateClass## class_name ();

#define IMPLIMENT_DYN _CREATE(class_name) /

static CBaseClass * CreateClass## class_name (){  /

       return new class_name;             /

};

分别放入需要创建的类的H文件和CPP文件就可以了~,当然,仅仅这样还不可以,因为我们不但要可以低耦合地创建对象,还需要把对象的创建方法和类名的映射存储起来,那么我们就还需要一个宏:

#define REGISTER_CLASS (class_name) /

RegisterFactory (class_name::CreateClass## class_name, #class_name);

在RegisterFactory函数中,我们需要一种结构,比如Map,将对应关系存储起来,以备以后的使用。

当然,我们也可以使用另一种方法,我们可以创建一个一般类,这个类可以进行映射关系的存储,提取,运行,或者动态映射的功能,我们让我们的反射类继承这个一般类就可以了。还是见代码吧(在2008下使用),如下所示:

(援引自http://blog.csdn.net/wrq147/archive/2010/05/18/5603262.aspx)

#include <string>

#include <map>

#include <iostream>

using namespace std;

typedef void* (*CreateFuntion)(void);

class ClassFactory

{

public:

static void* GetClassByName(std::string name)

{ std::map<std::string,CreateFuntion>::const_iterator find;

find = m_clsMap.find(name);

if(find==m_clsMap.end())

{

return NULL;

}

else

{

return find->second();

}

}

static void RegistClass(std::string name,CreateFuntion method)

{

m_clsMap.insert(std::make_pair(name,method));

}

private:

static std::map<std::string,CreateFuntion> m_clsMap;

};

std::map<std::string, CreateFuntion> ClassFactory::m_clsMap;

class RegistyClass

{

public:

RegistyClass(std::string name, CreateFuntion method)

{

ClassFactory::RegistClass(name, method);

}

};

template<class T, const char name[]>

class Register

{

public:

Register()

{

const RegistyClass tmp=rc;

}

static void* CreateInstance()

{

return new T;

}

public:

static const RegistyClass rc;

};

template<class T,const char name[]>

const RegistyClass Register<T,name>::rc(name, Register<T, name>::CreateInstance);

#define DEFINE_CLASS(class_name) /

char NameArray[]=#class_name;/

class class_name:public Register<class_name, NameArray>

#define DEFINE_CLASS_EX(class_name,father_class) /

char NameArray[]=#class_name;/

class class_name:public Register<class_name, NameArray>,public father_class

DEFINE_CLASS(CG)

{

public:

void Display()

{

printf("I am Here/n");

}

};

int main(int tt)

{

CG* tmp=(CG*)ClassFactory::GetClassByName("CG");

tmp->Display();

return 0;

}

ITEM2:动态识别

所谓的RTTI(Run-Time Type Information)也就是运行时类型检查,在C++中的自有动态技术应该就是typeid和dynamic_cast了,找到一段typeid 的例程,如下:

#include <string.h>

#include <iostream.h>

#include <typeinfo.h>

#include <stdio.h>

class Base

{

public:

Base()

{

strcpy(name,"Base");

}

virtual void display()

{

cout<<"Display Base."<<endl;

}

protected:

char name[64];

};

class Child1:public Base

{

public:

Child1()

{

strcpy(name,"Child1");

}

void display()

{

cout<<"Display Child1."<<endl;

}

};

class Child2:public Base

{

public:

Child2()

{

strcpy(name,"Child2");

}

void display()

{

cout<<"Display Child2."<<endl;

}

};

void Process(Base *type)

{

if( (typeid(Child1)) == (typeid(*type)) )

{

((Child1*)type)->display();

}

else if( (typeid(Child2)) == (typeid(*type)) )

{

((Child2*)type)->display();

}

else

{

cout<<"Unknow type!"<<endl;

}

}

int main(void)

{

Base *pT1 = new Child1();

Base *pT2 = new Child2();

Process(pT1);

Process(pT2);

printf("OK/n");

return 0;

}

注意:

1.#include "typeinfo.h"

2.编译选项/GR setting ->c++ -> c++ language -> Enable Run-Time Type Infomation

3.typeid的使用

ITEM3:C++ 的“反射”技术

找到了下面的介绍,看看成型的操作吧

Lit Window Library

来自http://sourceforge.net/projects/litwindow 大概看了一下,使用了宏建立了一个比较复杂的数据结构,用来提供成员反查以及成员访问。

tinybind

来自http://sourceforge.net/projects/tinybind/ 这个应该不算是反射,不过通过了定义一个Binding函数实现成员和XML的Element之间的绑定,自动实现了XML<->class,对实现C++的“反射”也有一定的参考作用。

OODBC

来自http://www.garret.ru/~knizhnik/cpp.html 这个也应该不算是反射,也是通过宏建立一个记录成员变量在类中的偏移位置的链表。自动实现数据库字段与成员的绑定,有点Hibernate的味道。呵呵。同时,作者提供的另外几个例如FastDB、GigaBase、goods、POST++都使用了类似的技术。

很多都需要你自己慢慢的思考,也许这就是CPP魅力

反射,To be, or not to be...