采用这种方式,有一个关键问题,便是在工厂中注册类名。我们的办法是针对于每一个类(Class),定义一个注册类(ClassReg),在注册类(ClassReg)的构造函数中注册此类(Class),然后再定义一个注册类的全局对象,在该全局对象初始化时,便会执行注册代码完成注册。
看到到这里懒人不乐意了,难道我们每写一个类,还要写一个相应的注册类?于是有人提出了使用宏来替换相应的代码,这样便大大减少了重复代码量。
采用宏当然可以,但是只能满足部分懒人。还有一部分人更懒,他们连使用这个宏完成注册都不想干,是呀,每写完一个类,还要在类后面使用宏来注册,这样确实还是比较麻烦。而且这样代码不够美观,也不便于维护,同时采用宏来转换类名,遇到命名空间,嵌套类,会非常麻烦,我们必须在注册的时候,把名字写全,比如REG_CLASS(MyNameSpace::MyClass::MyStruct)。
那么有没有更好的方法呢?当然有,我们可以用类模板来实现这种功能。设想这种方式,若我们要定义一个类MyClass,并且想让此类支持动态创建,那么我们只需这样定义即可class MyClass : public DynamicCreate<MyClass>{};。这样是不是清晰多了?下面请看代码:
DynamicFactory.h文件
- #ifndef __DYNAMIC_FACTORY_H__
- #define __DYNAMIC_FACTORY_H__
- #ifdef __GNUC__
- #include <cxxabi.h>
- #endif
- #include <assert.h>
- #include <string.h>
- #include <stdlib.h>
- #include <map>
- #include <string>
- #include <typeinfo>
- // 动态对象基类
- class DynamicObject
- {
- public:
- DynamicObject() {}
- virtual ~DynamicObject() {}
- };
- // 动态对象创建工厂
- class DynamicFactory
- {
- public:
- typedef DynamicObject* (*CreateFunction)();
- static DynamicFactory & Instance()
- {
- static DynamicFactory fac;
- return fac;
- }
- // 解析类型名称(转换为 A::B::C 的形式)
- static std::string ReadTypeName(const char * name)
- {
- // 这里省略,具体代码在最后给出
- ...
- }
- bool Regist(const char * name, CreateFunction func)
- {
- if (!func)
- {
- return false;
- }
- std::string type_name = ReadTypeName(name);
- return _create_function_map.insert(std::make_pair(type_name, func)).second;
- }
- DynamicObject * Create(const std::string & type_name)
- {
- if (type_name.empty())
- {
- return NULL;
- }
- std::map<std::string, CreateFunction>::iterator it = _create_function_map.find(type_name);
- if (it == _create_function_map.end())
- {
- return NULL;
- }
- return it->second();
- }
- template<typename T>
- T * Create(const std::string & type_name)
- {
- DynamicObject * obj = Create(type_name);
- if (!obj)
- {
- return NULL;
- }
- T * real_obj = dynamic_cast<T*>(obj);
- if (!real_obj)
- {
- delete obj;
- return NULL;
- }
- return real_obj;
- }
- public:
- std::map<std::string, CreateFunction> _create_function_map;
- };
- // 动态对象创建器
- template<typename T>
- class DynamicCreate : public DynamicObject
- {
- public:
- static DynamicObject * CreateObject()
- {
- return new T();
- }
- struct Registor
- {
- Registor()
- {
- if (!DynamicFactory::Instance().Regist(typeid(T).name(), CreateObject))
- {
- assert(false);
- }
- }
- inline void do_nothing()const { }
- };
- static Registor s_registor;
- public:
- DynamicCreate()
- {
- s_registor.do_nothing();
- }
- virtual ~DynamicCreate()
- {
- s_registor.do_nothing();
- }
- };
- template <typename T>
- typename DynamicCreate<T>::Registor DynamicCreate<T>::s_registor;
- #endif
#ifndef __DYNAMIC_FACTORY_H__
#define __DYNAMIC_FACTORY_H__
#ifdef __GNUC__
#include <cxxabi.h>
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include <string>
#include <typeinfo>
// 动态对象基类
class DynamicObject
{
public:
DynamicObject() {}
virtual ~DynamicObject() {}
};
// 动态对象创建工厂
class DynamicFactory
{
public:
typedef DynamicObject* (*CreateFunction)();
static DynamicFactory & Instance()
{
static DynamicFactory fac;
return fac;
}
// 解析类型名称(转换为 A::B::C 的形式)
static std::string ReadTypeName(const char * name)
{
// 这里省略,具体代码在最后给出
...
}
bool Regist(const char * name, CreateFunction func)
{
if (!func)
{
return false;
}
std::string type_name = ReadTypeName(name);
return _create_function_map.insert(std::make_pair(type_name, func)).second;
}
DynamicObject * Create(const std::string & type_name)
{
if (type_name.empty())
{
return NULL;
}
std::map<std::string, CreateFunction>::iterator it = _create_function_map.find(type_name);
if (it == _create_function_map.end())
{
return NULL;
}
return it->second();
}
template<typename T>
T * Create(const std::string & type_name)
{
DynamicObject * obj = Create(type_name);
if (!obj)
{
return NULL;
}
T * real_obj = dynamic_cast<T*>(obj);
if (!real_obj)
{
delete obj;
return NULL;
}
return real_obj;
}
public:
std::map<std::string, CreateFunction> _create_function_map;
};
// 动态对象创建器
template<typename T>
class DynamicCreate : public DynamicObject
{
public:
static DynamicObject * CreateObject()
{
return new T();
}
struct Registor
{
Registor()
{
if (!DynamicFactory::Instance().Regist(typeid(T).name(), CreateObject))
{
assert(false);
}
}
inline void do_nothing()const { }
};
static Registor s_registor;
public:
DynamicCreate()
{
s_registor.do_nothing();
}
virtual ~DynamicCreate()
{
s_registor.do_nothing();
}
};
template <typename T>
typename DynamicCreate<T>::Registor DynamicCreate<T>::s_registor;
#endif
代码不多,就不做解释了。
测试代码mian.cpp
- #include <stdio.h>
- #include "DynamicFactory.h"
- class Test1 : public DynamicCreate<Test1>
- {
- public:
- // 注意:使用gcc,一定要显示申明构造函数,否则不会执行注册代码
- Test1() {}
- };
- namespace OK {
- struct Test2 : public DynamicCreate<Test2>
- {
- Test2() {}
- class Test3 : public DynamicCreate<Test3>
- {
- public:
- Test3() {}
- };
- };
- struct Test4 : public DynamicCreate<Test4>
- {
- Test4() {}
- };
- }
- using namespace OK;
- //测试代码
- int main()
- {
- Test1 * p1 = DynamicFactory::Instance().Create<Test1>("Test1");
- printf("Create Test1 %s\n", (p1 ? "success" : "failure"));
- OK::Test2 * p2 = DynamicFactory::Instance().Create<OK::Test2>("OK::Test2");
- printf("Create OK::Test2 %s\n", (p2 ? "success" : "failure"));
- OK::Test2::Test3 * p3 = DynamicFactory::Instance().Create<OK::Test2::Test3>("OK::Test2::Test3");
- printf("Create OK::Test2::Test3 %s\n", (p3 ? "success" : "failure"));
- OK::Test4 * p4 = DynamicFactory::Instance().Create<OK::Test4>("OK::Test4");
- printf("Create OK::Test4 %s\n", (p4 ? "success" : "failure"));
- return 0;
- }
#include <stdio.h>
#include "DynamicFactory.h"
class Test1 : public DynamicCreate<Test1>
{
public:
// 注意:使用gcc,一定要显示申明构造函数,否则不会执行注册代码
Test1() {}
};
namespace OK {
struct Test2 : public DynamicCreate<Test2>
{
Test2() {}
class Test3 : public DynamicCreate<Test3>
{
public:
Test3() {}
};
};
struct Test4 : public DynamicCreate<Test4>
{
Test4() {}
};
}
using namespace OK;
//测试代码
int main()
{
Test1 * p1 = DynamicFactory::Instance().Create<Test1>("Test1");
printf("Create Test1 %s\n", (p1 ? "success" : "failure"));
OK::Test2 * p2 = DynamicFactory::Instance().Create<OK::Test2>("OK::Test2");
printf("Create OK::Test2 %s\n", (p2 ? "success" : "failure"));
OK::Test2::Test3 * p3 = DynamicFactory::Instance().Create<OK::Test2::Test3>("OK::Test2::Test3");
printf("Create OK::Test2::Test3 %s\n", (p3 ? "success" : "failure"));
OK::Test4 * p4 = DynamicFactory::Instance().Create<OK::Test4>("OK::Test4");
printf("Create OK::Test4 %s\n", (p4 ? "success" : "failure"));
return 0;
}
输出:
- [programmer@localhost test]$ ./test
- Create Test1 success
- Create OK::Test2 success
- Create OK::Test2::Test3 success
- Create OK::Test4 success
[programmer@localhost test]$ ./test
Create Test1 success
Create OK::Test2 success
Create OK::Test2::Test3 success
Create OK::Test4 success
下面给出上面省略的 ReadTypeName函数代码
- // 解析类型名称(转换为 A::B::C 的形式)
- // GCC 的type_info::name()输出的名称很猥琐,这里只做简单的解析,只支持自定义的结构体(非模板),类(非模板)、枚举、联合
- static std::string ReadTypeName(const char * name)
- {
- #ifndef __GNUC__
- const char * p = strstr(name, " ");
- if (p)
- {
- size_t prev_len = (size_t)(p - name);
- if (memcmp(name, "class", prev_len) == 0 ||
- memcmp(name, "struct", prev_len) == 0 ||
- memcmp(name, "enum", prev_len) == 0 ||
- memcmp(name, "union", prev_len) == 0)
- {
- p += 1;
- return std::string(p);
- }
- }
- return std::string(name);
- #else
- char * real_name = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
- std::string real_name_string(real_name);
- free(real_name);
- return real_name_string;
- #endif
- }
// 解析类型名称(转换为 A::B::C 的形式)
// GCC 的type_info::name()输出的名称很猥琐,这里只做简单的解析,只支持自定义的结构体(非模板),类(非模板)、枚举、联合
static std::string ReadTypeName(const char * name)
{
#ifndef __GNUC__
const char * p = strstr(name, " ");
if (p)
{
size_t prev_len = (size_t)(p - name);
if (memcmp(name, "class", prev_len) == 0 ||
memcmp(name, "struct", prev_len) == 0 ||
memcmp(name, "enum", prev_len) == 0 ||
memcmp(name, "union", prev_len) == 0)
{
p += 1;
return std::string(p);
}
}
return std::string(name);
#else
char * real_name = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
std::string real_name_string(real_name);
free(real_name);
return real_name_string;
#endif
}