C++实现反射机制
2016-11-29 18:17
447 查看
话不多说,先上段代码的运行结果:
class TestA:public Object
{
DECLARE_CLASS()
public:
TestA() {std::cout << "TestA constructor" << std::endl;}
~TestA(){std::cout << "TestA destructor" << std::endl;}
};
IMPLEMENT_CLASS("testA_interface", TestA)
int main()
{
Object* obj = Object::CreateObject("testA_interface");
delete obj;
return 0;
}
关键就一个功能——根据字符串创建了类对象
开发中经常会遇到根据不同借口创建不同类实例的情况,一般的做法就是if......else if...else if这样一直判断。比如说接口名是testA_interface,就创建一个TestA对象。如果接口不多还好办,如果接口有成千上万呢?维护起来都难办。那么有没有一种简单的方法?下面慢慢探究。
先说一下一般的思路:
常规的思路就是说建立一个map表,以接口名未key,构造函数为value。但有个问题——我们没办法定义一个构造函数的函数指针!
虽然用map的方法不可行,但这确是一个稚形,以这个为基础,一步一步解决问题(如果是C语言,这里没法用map,其实顶一个结构体就可以了)。
问题一:没法定义构造函数的函数指针
直接从构造函数指针不行,那就加一个中间层,没有什么是不能通过加一层来解决的,如果有,那就加两层。具体的做法就是map中不存构造函数了,而是存另一个类的对象,类的定义如下:
class ClassInfo
{
public:
ClassInfo(){}
ClassInfo(const std::string &interface_name, ObjectConstructorFn ctor)
{
m_interface_name = interface_name;
m_object_constructor = ctor;
Object::Register(this);
}
Object *CreateObject()const
{
return m_object_constructor ? (*m_object_constructor)() : 0;
}
public:
std::string m_interface_name;
ObjectConstructorFn m_object_constructor;
};
很明显,我们把接口名跟构造函数聚合到了一个结构里面,ObjectConstructorFn是定义的一个函数指针,指向了每个类的构造函数。其实这个地方我们把原来map中的key和value一起当做value了。由此我们可以定义一个map
std::map<std::string, ClassInfo *> *class_info_map = new std::map<std::string, ClassInfo*>();
在调用的时候只需要find()->CreateObject()就可以了。
问题二:接口类的管理
就算这个问题不放这里我们也知道,各个接口对应的类它们肯定有一个公有的基类,其次这个地方恩把所有类继承一公有基类也方便我们管理。所有最简基类的定义如下:
class Object
{
public:
Object(){}
virtual ~Object(){}
static void Register(ClassInfo* ci);
static Object* CreateObject(const std::string &interface_name);
}; 关键成员函数有两个,register和createobject,本来是想把这个类设置成单例的,也就是说构造函数应该设为private,但是由于这个类是基类,在创建子类对象的时候会调用基类的构造函数,所以这儿就设成了public,如果createobject来创建对象。而对于register成员函数,它就是根据接口把ClassInfo插入到class_info_map,最简单粗暴的方法就是class_info_map[ci->interface_name]
= ci。由前面ClassInfo定义可知,ci已经保存了接口名返回实例的函数。
问题三:子类的实现
目前为止其他都可以了,就差子类的实现了,前面说了,ClassInfo标示了一个接口名和接口的对应关系。所以子类需要包含一个ClassInfo的成员变量。定义两个宏:
#define DECLARE_CLASS() \
protected: \
static ClassInfo ms_classinfo; \
public: \
static Object* CreateObject();
#define IMPLEMENT_CLASS(interface_name, class_name) \
ClassInfo class_name::ms_classinfo(interface_name,(ObjectConstructorFn)class_name::CreateObject);\
Object* class_name::CreateObject() \
{ return new class_name;} 这两个宏定义了所有子类需要实现的部分,所以只要直接引入这两个宏就可以了,在宏中定义了唯一标示接口名与类对应关系的ms_classinfo变量,此外有实现了返回每一个类型对象的CreateObject函数。
下面贴一下完整的代码
#include <iostream>
#include <string>
#include <map>
using namespace std;
#define DECLARE_CLASS() \
protected: \
static ClassInfo ms_classinfo; \
public: \
static Object* CreateObject();
#define IMPLEMENT_CLASS(interface_name, class_name) \
ClassInfo class_name::ms_classinfo(interface_name,(ObjectConstructorFn)class_name::CreateObject);\
Object* class_name::CreateObject() \
{ return new class_name;}
class ClassInfo;
class Object;
typedef Object* (*ObjectConstructorFn)();
class Object
{
protected:
Object(){}
public:
virtual ~Object(){}
static void Register(ClassInfo* ci);
static Object* CreateObject(std::string name);
static std::map<std::string, ClassInfo *> *classInfoMap;
};
class ClassInfo
{
public:
ClassInfo(const std::string className, ObjectConstructorFn ctor);
ClassInfo();
Object *CreateObject()const;
public:
std::string m_className;
ObjectConstructorFn m_objectConstructor;
};
std::map<std::string, ClassInfo *> *Object::classInfoMap = new std::map<std::string, ClassInfo*>();
void Object::Register(ClassInfo* ci)
{
if (NULL != ci && classInfoMap->find(ci->m_className) == classInfoMap->end())
{
classInfoMap->insert(std::map<std::string, ClassInfo*>::value_type(ci->m_className, ci));
}
}
Object* Object::CreateObject(std::string name)
{
std::map<std::string, ClassInfo*>::const_iterator iter = classInfoMap->find(name);
if (iter != classInfoMap->end())
{
return iter->second->CreateObject();
}
return NULL;
}
ClassInfo::ClassInfo(const std::string className, ObjectConstructorFn ctor):m_className(className), m_objectConstructor(ctor)
{
Object::Register(this);
}
ClassInfo::ClassInfo()
{
}
Object *ClassInfo::CreateObject()const
{
return m_objectConstructor ? (*m_objectConstructor)() : 0;
}
class Test:public Object
{
DECLARE_CLASS()
public:
Test(){cout << "Test constructor" << endl;}
~Test(){cout << "Test destructor" << endl;}
};
IMPLEMENT_CLASS("xxxx", Test)
int main()
{
Object* obj = Object::CreateObject("xxxx");
delete obj;
return 0;
} 熟悉MFC的同学应该知道,MFC中有一个BEGIN_MESSAGE_MAP,它也是实现了不同消息ID与不同处理函数的映射,实现原理和这个类似。
class TestA:public Object
{
DECLARE_CLASS()
public:
TestA() {std::cout << "TestA constructor" << std::endl;}
~TestA(){std::cout << "TestA destructor" << std::endl;}
};
IMPLEMENT_CLASS("testA_interface", TestA)
int main()
{
Object* obj = Object::CreateObject("testA_interface");
delete obj;
return 0;
}
关键就一个功能——根据字符串创建了类对象
开发中经常会遇到根据不同借口创建不同类实例的情况,一般的做法就是if......else if...else if这样一直判断。比如说接口名是testA_interface,就创建一个TestA对象。如果接口不多还好办,如果接口有成千上万呢?维护起来都难办。那么有没有一种简单的方法?下面慢慢探究。
先说一下一般的思路:
常规的思路就是说建立一个map表,以接口名未key,构造函数为value。但有个问题——我们没办法定义一个构造函数的函数指针!
虽然用map的方法不可行,但这确是一个稚形,以这个为基础,一步一步解决问题(如果是C语言,这里没法用map,其实顶一个结构体就可以了)。
问题一:没法定义构造函数的函数指针
直接从构造函数指针不行,那就加一个中间层,没有什么是不能通过加一层来解决的,如果有,那就加两层。具体的做法就是map中不存构造函数了,而是存另一个类的对象,类的定义如下:
class ClassInfo
{
public:
ClassInfo(){}
ClassInfo(const std::string &interface_name, ObjectConstructorFn ctor)
{
m_interface_name = interface_name;
m_object_constructor = ctor;
Object::Register(this);
}
Object *CreateObject()const
{
return m_object_constructor ? (*m_object_constructor)() : 0;
}
public:
std::string m_interface_name;
ObjectConstructorFn m_object_constructor;
};
很明显,我们把接口名跟构造函数聚合到了一个结构里面,ObjectConstructorFn是定义的一个函数指针,指向了每个类的构造函数。其实这个地方我们把原来map中的key和value一起当做value了。由此我们可以定义一个map
std::map<std::string, ClassInfo *> *class_info_map = new std::map<std::string, ClassInfo*>();
在调用的时候只需要find()->CreateObject()就可以了。
问题二:接口类的管理
就算这个问题不放这里我们也知道,各个接口对应的类它们肯定有一个公有的基类,其次这个地方恩把所有类继承一公有基类也方便我们管理。所有最简基类的定义如下:
class Object
{
public:
Object(){}
virtual ~Object(){}
static void Register(ClassInfo* ci);
static Object* CreateObject(const std::string &interface_name);
}; 关键成员函数有两个,register和createobject,本来是想把这个类设置成单例的,也就是说构造函数应该设为private,但是由于这个类是基类,在创建子类对象的时候会调用基类的构造函数,所以这儿就设成了public,如果createobject来创建对象。而对于register成员函数,它就是根据接口把ClassInfo插入到class_info_map,最简单粗暴的方法就是class_info_map[ci->interface_name]
= ci。由前面ClassInfo定义可知,ci已经保存了接口名返回实例的函数。
问题三:子类的实现
目前为止其他都可以了,就差子类的实现了,前面说了,ClassInfo标示了一个接口名和接口的对应关系。所以子类需要包含一个ClassInfo的成员变量。定义两个宏:
#define DECLARE_CLASS() \
protected: \
static ClassInfo ms_classinfo; \
public: \
static Object* CreateObject();
#define IMPLEMENT_CLASS(interface_name, class_name) \
ClassInfo class_name::ms_classinfo(interface_name,(ObjectConstructorFn)class_name::CreateObject);\
Object* class_name::CreateObject() \
{ return new class_name;} 这两个宏定义了所有子类需要实现的部分,所以只要直接引入这两个宏就可以了,在宏中定义了唯一标示接口名与类对应关系的ms_classinfo变量,此外有实现了返回每一个类型对象的CreateObject函数。
下面贴一下完整的代码
#include <iostream>
#include <string>
#include <map>
using namespace std;
#define DECLARE_CLASS() \
protected: \
static ClassInfo ms_classinfo; \
public: \
static Object* CreateObject();
#define IMPLEMENT_CLASS(interface_name, class_name) \
ClassInfo class_name::ms_classinfo(interface_name,(ObjectConstructorFn)class_name::CreateObject);\
Object* class_name::CreateObject() \
{ return new class_name;}
class ClassInfo;
class Object;
typedef Object* (*ObjectConstructorFn)();
class Object
{
protected:
Object(){}
public:
virtual ~Object(){}
static void Register(ClassInfo* ci);
static Object* CreateObject(std::string name);
static std::map<std::string, ClassInfo *> *classInfoMap;
};
class ClassInfo
{
public:
ClassInfo(const std::string className, ObjectConstructorFn ctor);
ClassInfo();
Object *CreateObject()const;
public:
std::string m_className;
ObjectConstructorFn m_objectConstructor;
};
std::map<std::string, ClassInfo *> *Object::classInfoMap = new std::map<std::string, ClassInfo*>();
void Object::Register(ClassInfo* ci)
{
if (NULL != ci && classInfoMap->find(ci->m_className) == classInfoMap->end())
{
classInfoMap->insert(std::map<std::string, ClassInfo*>::value_type(ci->m_className, ci));
}
}
Object* Object::CreateObject(std::string name)
{
std::map<std::string, ClassInfo*>::const_iterator iter = classInfoMap->find(name);
if (iter != classInfoMap->end())
{
return iter->second->CreateObject();
}
return NULL;
}
ClassInfo::ClassInfo(const std::string className, ObjectConstructorFn ctor):m_className(className), m_objectConstructor(ctor)
{
Object::Register(this);
}
ClassInfo::ClassInfo()
{
}
Object *ClassInfo::CreateObject()const
{
return m_objectConstructor ? (*m_objectConstructor)() : 0;
}
class Test:public Object
{
DECLARE_CLASS()
public:
Test(){cout << "Test constructor" << endl;}
~Test(){cout << "Test destructor" << endl;}
};
IMPLEMENT_CLASS("xxxx", Test)
int main()
{
Object* obj = Object::CreateObject("xxxx");
delete obj;
return 0;
} 熟悉MFC的同学应该知道,MFC中有一个BEGIN_MESSAGE_MAP,它也是实现了不同消息ID与不同处理函数的映射,实现原理和这个类似。
相关文章推荐
- C++实现 反射 机制( 即根据 类名 创建 类实例)Create C++ Object Dynamically
- C++实现反射机制(一)
- C++反射机制的实现
- C++反射机制的实现
- object c++如何实现反射机制
- C++反射机制的实现(转)
- c++实现反射机制(两篇)
- C++ 反射机制的实现Demo
- C++反射机制的实现
- C++ 实现通过类名来进行实例化(反射机制?)
- C++反射机制具体实现方法详解(转帖:原作者不详)
- C++反射机制的实现
- C++实现反射机制
- C++实现 反射 机制(根据 类名 创建 类的对象) C++ Create Object Dynamically
- 一个新的对象创建机制的思考--C++下实现类似于Java的对象管理机制及反射
- object c++如何实现反射机制
- c++反射机制的实现(完整代码,相当靠谱)
- c++实现反射机制(两篇)
- C++实现反射机制(一)
- C++实现反射机制