C++动态创建类的实例

时间:2022-08-06 21:16:15

写在前面:首先声明,C++实际上是不可以动态创建类的实例的。

下面简单做一个解释,所谓动态创建类的实例是指在程序运行过程中创建并使用一个“未知”的类。而“未知”是指在程序编译时并不知道有哪些类是需要动态创建的。对于C++这门语言来说,编译时不知道的类是不可以在运行时使用的。所以我说C++是不可以的。

不过C++可以做到另一件事情,基本可以满足大多数类似的需求。

我描述为通过类名称创建类的实例。

进入正题。

首先描述一下需求:

编写一个程序实现在程序运行过程中通过类名称(即字符串变量)创建该类的实例,且在主程序中不出现该类的声明。

然后进行分析设计:

1.在主程序中不出现类的声明,还需要用这个类。那很自然就会想到用基类指针实现。

2.创建一个指向该类的基类指针,则需要使用new运算符。

3.通过类名调用相应的new运算符,则需要使用map加函数指针。

4.最后,如何在主函数执行之前构造该map,则需要用到静态成员在主函数运行前进行创建的机制。

下面给出代码实现:

首先有一个CObject类作为基类,由它派生出CObjectA和CObjectB两个需要动态创建的子类。

Object.h

 1 #ifndef __C_OBJECT_H_
 2 #define __C_OBJECT_H_
 3 
 4 #include "ObjectFactory.h"
 5 
 6 class CObject
 7 {
 8 public:
 9     CObject(): className("CObject") {}
10     virtual ~CObject(){}
11     virtual const std::string GetClassName()
12     {
13         return className;
14     }
15 private:
16     std::string className;
17 };
18 
19 #endif //__C_OBJECT_H_

ObjectA.h

 1 #ifndef __C_OBJECT_A_H_
 2 #define __C_OBJECT_A_H_
 3 
 4 #include "Object.h"
 5 
 6 class CObjectA : public CObject
 7 {
 8 public:
 9     CObjectA(): className("CObjectA") {}
10     ~CObjectA(){}
11     const std::string GetClassName()
12     {
13         return className;
14     }
15 private:
16     std::string className;
17 };
18 
19 REGISTER_CLASS(CObjectA);
20 
21 #endif //__C_OBJECT_A_H_

ObjectB.h

 1 #ifndef __C_OBJECT_B_H_
 2 #define __C_OBJECT_B_H_
 3 
 4 #include "Object.h"
 5 
 6 class CObjectB : public CObject
 7 {
 8 public:
 9     CObjectB(): className("CObjectB") {}
10     ~CObjectB(){}
11     const std::string GetClassName()
12     {
13         return className;
14     }
15 private:
16     std::string className;
17 };
18 
19 REGISTER_CLASS(CObjectB);
20 
21 #endif //__C_OBJECT_B_H_

然后重点就来了,上面两个类里面都有的宏定义REGISTER_CLASS。实际上就是声明一个带有静态成员的注册类,通过初始化该静态成员实现构造动态创建map。

ObjectFactory.h

 1 #ifndef __C_OBJECT_FACTORY_H_
 2 #define __C_OBJECT_FACTORY_H_
 3 
 4 #include <map>
 5 #include <string>
 6 
 7 typedef void* (*NewInstancePt)();
 8 
 9 class CObjectFactory
10 {
11 public:
12     static void* CreateObject(const char *className)
13     {
14         std::map<std::string, NewInstancePt>::const_iterator it;
15         it = dynCreateMap.find(className);
16         if(it == dynCreateMap.end())
17             return NULL;
18         else
19         {
20             NewInstancePt np = it->second;
21             return np();
22         }
23     }
24 
25     static void RegisterClass(const char *className, NewInstancePt np)
26     {
27         dynCreateMap[className] = np;
28     }
29 private:
30     static std::map<std::string, NewInstancePt> dynCreateMap;
31 };
32 
33 std::map<std::string, NewInstancePt> CObjectFactory::dynCreateMap;
34 
35 class Register
36 {
37 public:
38     Register(const char *className, NewInstancePt np)
39     {
40         CObjectFactory::RegisterClass(className, np);
41     }
42 };
43 
44 #define REGISTER_CLASS(class_name) \
45 class class_name##Register \
46 { \
47 public: \
48     static void* NewInstance() \
49     { \
50         return new class_name(); \
51     } \
52 private: \
53     static Register reg; \
54 }; \
55 Register class_name##Register::reg(#class_name, class_name##Register::NewInstance)
56 
57 #endif //__C_OBJECT_FACTORY_H_

最后,当然还有如何使用的主函数内容。

RTTI.cpp

 1 #include <stdio.h>
 2 #include "ObjectFactory.h"
 3 #include "Object.h"
 4 #include "ObjectA.h"
 5 #include "ObjectB.h"
 6 
 7 int main(int argc, const char *argv[])
 8 {
 9     CObject *objA = static_cast<CObject *>(CObjectFactory::CreateObject("CObjectA"));
10     std::string className;
11     if(objA == NULL)
12     {
13         printf("[ERROR] Can't Create Class ObjectA!\n");
14     }
15     else
16     {
17         className = objA->GetClassName();
18         printf("[OK] Create %s !\n", className.c_str());
19     }
20 
21     CObject *objB = static_cast<CObject *>(CObjectFactory::CreateObject("CObjectB"));
22     if(objB == NULL)
23     {
24         printf("[ERROR] Can't Create Class ObjectB!\n");
25     }
26     else
27     {
28         className = objB->GetClassName();
29         printf("[OK] Create %s !\n", className.c_str());
30     }
31 
32     return 0;
33 }

这样就完成了所谓的动态创建。这里需要注意的是在主函数所在的文件里面需要include所有的需要动态创建的类,否则的话在编译的过程中这些类以及其注册类就根本不会被编译,也就不会构建动态创建map,整个机制也就失效了。这也就是我说的C++实际上是不可以动态创建类的原因。

不得不说,如果想要彻底的动态创建,建议使用Java。简单看看Java的反射机制和ClassLoader就会知道原来动态加载如此容易。。。