C++对象动态生成(Dynamic Create)的简单实现

http://blog.csdn.net/torytin/article/details/7557698


以前一直是C++的coder,最近由于到了另一家公司,因此开始写Java项目,相信C++的程序员都会对java语言原生支持的动态生成很是羡慕,但是C++不支持反射(reflection),也就无法根据类名动态创建对象,MFC的做法是继承CObject并用DECLARE_DYNCREATE宏来实现,MFC这么实现是由于一些系统遗留问题,感觉用起来不是那么的friendly。今天下午坐着无聊,仿造java的结构构思了下C++的动态生成实现方法。

基本想法:

1.java的所有类都默认继承自Object类,在C++中我们也需要这么一个公用的基类。

2.java中每个类都有对应的一个Class类,用来动态创建类对象,我们也定义一个Class类

3.java中可以用Class.forName(String className)来获得相应的Class类,我们的Class类也应该支持这种方式

4.java中用Class.newInstance()动态生成类的实例,其实Class类在这里就相当于一个Factory,我们也提供这种方式

基本上,只要实现了上述4个条件,类的动态创建就跟java的方式差不多了,具体代码如下:

核心代码:

Class.h

[cpp]  view plain  copy
  1. /* 
  2.  * C++对象动态创建(Dynamic Create)简单实现 
  3.  *使用方法:对每一个需要动态创建的类,继承自Object类,并调用Class::Register(className)注册一下即可 
  4.  *  Created on: 2012-5-11 
  5.  *      Author: torytin 
  6.  */  
  7.   
  8. #ifndef CLASS_H_  
  9. #define CLASS_H_  
  10. #include   
  11. #include   
  12. using namespace std;  
  13. /** 
  14.  * Object类,需要动态生成的类都必须继承该类 
  15.  * 目前该类无任何功能,只是一个标记 
  16.  * @author torytin 
  17.  */  
  18. class Class;  
  19. class Object {  
  20. public:  
  21.     //用来保存创建的Class类  
  22.     static const Class *const theClass;  
  23. };  
  24. /** 
  25.  * 对象工厂模板类,该类用来生成具体的对象 
  26.  * @author torytin 
  27.  * 
  28.  */  
  29. template<class T> class ObjectFactory {  
  30. public:  
  31.     static Object *create() {  
  32.         return new T();  
  33.     }  
  34.     ;  
  35. };  
  36. /** 
  37.  * Class类,用来存储类信息 
  38.  * 为了可以把具体的类型对用户隐藏,Class类没有设成模板类 
  39.  * 因为C++的模板类对象持有的时候必须指定具体的类名,如果设定为模板类 
  40.  * 使用的时候只能是Class<类名> *pClass,而不能是Class *pClass。 
  41.  * 用户还是需要知道具体类名,就失去了动态创建的意义,但为了达到动态创建的目的, 
  42.  * Class类的Register是一个template函数,具体的类型信息,需要用户在注册类的时候提供 
  43.  * @author torytin 
  44.  * 
  45.  */  
  46. class Class {  
  47. private:  
  48.     //创建对象的函数指针定义  
  49.     Object *(*factory)(void);  
  50.     //用来存储当前注册的所有可动态创建的Class  
  51.     static map classMap;  
  52.     //类的名称  
  53.     string name;  
  54.     //Class类不允许外部初始化  
  55.     Class() {  
  56.     }  
  57. public:  
  58.     /*** 
  59.      * Class类注册函数,该注册函数是template函数。 
  60.      * 用户需要提供T的具体类型和类的唯一标识符(一般为类名),比如生成Example类的Class: 
  61.      * Class::Register("Example"); 
  62.      * 参数: 
  63.      *      T:具体的类 
  64.      *      className:注册的名字(一般为类名,也可以为任意字符) 
  65.      */  
  66.     template<class T> static Class * Register(string className) {  
  67.         if (classMap.count(className)==0) {  
  68.             Class *cls = new Class();  
  69.             cls->factory = &ObjectFactory::create; //函数指针赋值,根据T的类型赋值相应的创建函数  
  70.             cls->name = className; //类名的唯一标识符  
  71.             classMap[className] = cls; //在这里注册该class类  
  72.         }  
  73.         return classMap[className];  
  74.     }  
  75.     ;  
  76.     //根据类的名字获得类对应的Class  
  77.     static Class *forName(string className);  
  78.     //生成类的实例  
  79.     Object *newInstance() const;  
  80.     //获得类名  
  81.     string getName() const;  
  82.     virtual ~Class();  
  83. };  
  84. #endif /* CLASS_H_ */  

Class.cpp
[cpp]  view plain  copy
  1. /* 
  2.  * Class.cpp 
  3.  * 
  4.  *  Created on: 2012-5-11 
  5.  *      Author: torytin 
  6.  */  
  7.   
  8. #include "Class.h"  
  9. map Class::classMap=map();  
  10. string Class::getName() const{  
  11.     return name;  
  12. }  
  13. Class *Class::forName(string className) {  
  14.     if (classMap.count(className) != 0) {  
  15.         return classMap[className];  
  16.     }  
  17.     return NULL;  
  18. }  
  19. Object *Class::newInstance() const {  
  20.         return factory();  
  21.     }  
  22.  Class::~Class() {  
  23. }  
  24.  //注册Object类信息,在这里,我们把返回的Class类存放在theClass中,方便后续使用  
  25.  const Class *const Object::theClass = Class::Register("Object");  
    用户类: 这里为了演示的需要定义了两个用户类

    Example.h

    [cpp]  view plain  copy
    1. /* 
    2.  * C++动态创建类示例 
    3.  * 对象必须继承Object类,并且必须有一个无参的构造函数 
    4.  * 定义对象后需要调用Class::Register函数注册当前类,可以把生成的Class保存在static变量中供后续使用 
    5.  *  Created on: 2012-5-11 
    6.  *      Author: torytin 
    7.  */  
    8.   
    9. #ifndef EXAMPLE_H_  
    10. #define EXAMPLE_H_  
    11.   
    12. #include "Class.h"  
    13. class Example: public Object{  
    14. public:  
    15.     //用来保存创建的Class类,这里保存只是为了方便使用,不是强制要求  
    16.     static const Class * theClass;  
    17.     Example();  
    18.     virtual ~Example();  
    19. };  
    20.   
    21. #endif /* EXAMPLE_H_ */  
    Example.cpp
    [cpp]  view plain  copy
    1. /* 
    2.  * Example.cpp 
    3.  * 
    4.  *  Created on: 2012-5-11 
    5.  *      Author: torytin 
    6.  */  
    7. #include   
    8. #include "Example.h"  
    9.   
    10. Example::Example() {  
    11.     std::cout<<"Example is initialized"<
    12. }  
    13.   
    14. Example::~Example() {  
    15. }  
    16. //注册Example类信息,在这里,我们把返回的Class类存放在theClass中,方便后续使用  
    17. const Class * Example::theClass = Class::Register("Example");  

    Example1.h
    [cpp]  view plain  copy
    1. /* 
    2.  * Example1.h 
    3.  * 
    4.  *  Created on: 2012-5-13 
    5.  *      Author: torytin 
    6.  */  
    7.   
    8. #ifndef EXAMPLE1_H_  
    9. #define EXAMPLE1_H_  
    10.   
    11. #include "Class.h"  
    12. class Example1: public Object {  
    13. public:  
    14.     static const Class * theClass;  
    15.     Example1();  
    16.     virtual ~Example1();  
    17. };  
    18.   
    19. #endif /* EXAMPLE1_H_ */  

    Example1.cpp

    [cpp]  view plain  copy
    1. /* 
    2.  * Example1.cpp 
    3.  * 
    4.  *  Created on: 2012-5-13 
    5.  *      Author: torytin 
    6.  */  
    7. #include   
    8. #include "Example1.h"  
    9.   
    10. Example1::Example1() {  
    11.     std::cout<<"Example1 is initialized";  
    12.   
    13. }  
    14.   
    15. Example1::~Example1() {  
    16.     // TODO Auto-generated destructor stub  
    17. }  
    18. //注册Example1类  
    19. const Class * Example1::theClass = Class::Register("Example1");  

    How to Use:

    [cpp]  view plain  copy
    1. //============================================================================  
    2. // Name        : dynamic.cpp  
    3. // Author      : torytin  
    4. // Version     :  
    5. // Copyright   :  
    6. // Description :Object dynamic create in C++, Ansi-style  
    7. //============================================================================  
    8.   
    9. #include   
    10. #include "Example.h"  
    11. using namespace std;  
    12.   
    13. void createExample(Class *cls){  
    14.     if(cls==Example::theClass){  
    15.         cout<<"it's a Example Class"<
    16.         cls->newInstance();  
    17.     }else{  
    18.         cout<<"it's not a Example Class"<
    19.     }  
    20. }  
    21. int main() {  
    22.     createExample(Class::forName("Example"));  
    23.     createExample(Class::forName("Example1"));  
    24.     return 0;  
    25. }  

    output

    [cpp]  view plain  copy
    1. it's a Example Class  
    2. Example is initialized  
    3. it's not a Example Class  

       这样c++就就基本实现了java的动态生成机制,相比java来说,我们继承Object的同时还需要调用Class::Register函数注册一下,上面对于Class对象的示例代码中是直接比较指针地址,用户也可以重写Class对象的operator==来根据Class的name是否相等进行比较。另外一个缺陷是无法判断一个类是否是一个类的子类实例,比如我再写一个类SubExample继承Example,但目前是无法判断一个SubExample是否是一个Example的,如果需要做到这点,可以保存整个类的继承关系图,就是Class初始化的时候再加一个父类型参数,然后把整个继承关系保存下来。可以参见完善版本:C++对象动态生成(Dynamic Create)的完善版本

     

    -------------------------------------------------------------我是分割线--------------------------------------------------------------

     

       对于zhouguidi 提出的模板类的动态创建问题,可能不只一个网友会遇到,这里贴出一些可能的实现思路和代码。由于C++模板类的实现机理是一个类定义应用于多个类,只有当用户指定具体的类型之后,类定义才真正完整,也就是说一个模板类可以生成无穷个类。对于动态创建模板类对象来说,我们不可能把这些无穷个类都进行注册,因此有以下两种解决方案:

    1.穷举法:对于所有用到的模板类,在程序开始的某一段代码里面进行穷举注册

    Class::Register>("TemplateExample");

    Class::Register>("TemplateExample");

    Class::Register>("TemplateExample");

    ……

    然后后续代码就可以通过Class::forName("TemplateExample")等来获得对应模板类的Class对象,这种方法比较容易理解,也比较通用,不管类型参数是基本类型还是自定义类型都可以使用,但代码有点冗余繁琐。

    2.自动注册:该方法的好处是不需要再写很多重复的Register语句,但需要对模板类的类型参数有一定的约定,因此只能应用于模板类的类型参数是自定义类型的情况,具体见代码

    TemplateExample.h

    [cpp]  view plain  copy
    1. /* 
    2.  * TemplateExample.h 
    3.  * 
    4.  *  Created on: 2012-11-27 
    5.  *      Author: Torytin 
    6.  */  
    7.   
    8. #ifndef TEMPLATEEXAMPLE_H_  
    9. #define TEMPLATEEXAMPLE_H_  
    10.   
    11. #include "Class.h"  
    12.   
    13. template <class T> class TemplateExample: public Object {  
    14. public:  
    15.     //用来保存创建的Class类,这里保存只是为了方便使用,不是强制要求  
    16.     static const Class * theClass;  
    17.     TemplateExample();  
    18.     virtual ~TemplateExample();  
    19. };  
    20.   
    21. #endif /* TEMPLATEEXAMPLE_H_ */  


    TemplateExample.cpp

    [cpp]  view plain  copy
    1. /* 
    2.  * TemplateExample.cpp 
    3.  * 
    4.  *  Created on: 2012-11-27 
    5.  *      Author: Torytin 
    6.  */  
    7. #include   
    8. #include "TemplateExample.h"  
    9.   
    10. template <class T> TemplateExample::TemplateExample() {  
    11.  std::cout<getName()+" is initialized"<
    12. }  
    13. template <class T> TemplateExample::~TemplateExample() {  
    14.     // TODO Auto-generated destructor stub  
    15. }  
    16.   
    17. //注册该模板类信息,在这里,要求模板参数T也是属于可以动态创建的对象,且有一个theClass的静态变量指向该类的Class对象  
    18. //也可以对T只要求实现某一个方法获得一个可以表述该类名字的唯一字符串,比如要求T实现T::getClassName()  
    19. template <class T> const Class * TemplateExample::theClass = Class::Register >("TemplateExample<"+T::theClass->getName()+">");  


    How to Use:

    [cpp]  view plain  copy
    1. //============================================================================  
    2. // Name        : templateTest.cpp  
    3. // Author      : torytin  
    4. // Version     :  
    5. // Copyright   :  
    6. // Description :template Object dynamic create in C++, Ansi-style  
    7. //============================================================================  
    8.   
    9. #include   
    10. #include "Example.h"  
    11. #include "Example1.h"  
    12. //注意这里是引入模板类的实现文件,因为对于模板类,使用前是需要知道类的完整定义的  
    13. #include "TemplateExample.cpp"  
    14. using namespace std;  
    15. void createTemplateExample(const Class *cls){  
    16.     if(cls==TemplateExample::theClass){  
    17.             cout<<"it's a TemplateExample Class,instance it"<
    18.             cls->newInstance();  
    19.         }else{  
    20.             cout<<"it's not a TemplateExample Class"<
    21.         }  
    22. }  
    23. int main() {  
    24.    //这里可以成功的通过类名字获得类的Class对象,前提是代码中必须出现过TemplateExample(出现位置无所谓)  
    25.    createTemplateExample(Class::forName("TemplateExample"));  
    26.    //代码中必须出现过TemplateExample,这里只是让它出现那么一下  
    27.    new TemplateExample();  
    28.    //这里可以直接用Class::forName方法获得TemplateExample的类对象,是因为createTemplateExample函数代码中出现过该类  
    29.    createTemplateExample(Class::forName("TemplateExample"));  
    30.    return 0;  
    31. }  

    output

    [cpp]  view plain  copy
    1. TemplateExample is initialized  
    2. it's not a TemplateExample Class  
    3. it's a TemplateExample Class,instance it  
    4. TemplateExample is initialized  

         今天重新跑了下该示例程序,发现还存在一个似乎跟编译器相关的问题,如果整个代码中都没有引用到某个类的theClass变量,那么该变量是不会初始化的,也就是Class::Register函数不会被调用,该类也就没有注册。因此我在TemplateExample的初始化函数中用了一下theClass->getName()来输出类的名字,以确保会初始化该变量,我用的是elipse的g++编译器(按我原来的理解,既然类生产了,必然会初始化类的静态成员,但实际不是,只有真正代码中使用到过才会初始化该静态成员变量,这应该是g++编译器的一个优化,不知道别的编译器会不会也做同样的处理)

    你可能感兴趣的:(UE4,C++)