和网上大多数实现一样,这里也是采用工厂方法来实现对象的动态创建。大致原理为,创建一个单例工厂类,其中维护一个map(类名->对象创建函数)。创建对象时,传入类名,然后根据此类名查询出创建函数,最后创建对象。
采用这种方式,有一个关键问题,便是在工厂中注册类名。我们的办法是针对于每一个类(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
代码不多,就不做解释了。
测试代码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;
- }
输出:
[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
- }