C++動態創建類的實例


寫在前面:首先聲明,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就會知道原來動態加載如此容易。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM