焦頭爛額的考試月終於過去了,終於有時間能停下來思考記錄一下這一個月學過的東西,首先先總結一下,在自己仿寫魂斗羅游戲時遇見的問題之一,人物在移動的時候如何去判斷什么時候掉入水中顯示水中畫面,什么時候敵人該開槍,這個時候我使用了一堆數字來描述地圖,如圖
但是在代碼實現時,就得用一大堆判斷,來判斷何時應該創建對象來調用成員函數,其代碼繁雜不說,更加降低了代碼的復用性,如果我想在其中添加功能,還得再修改代碼,這個時候我就想到了動態創建數組這個東西,根據我輸入的數字長度,數組可以自動去增長,那對象是不是可以動態的去創建呢?,可能是我搜索的有問題,在網上很少有介紹這方面的過程,我覺得還是有必要記錄一下,給其他人也提供一個借鑒
首先先用字符串去做一個實驗,添加三個類,我想通過輸入一個字符串就能創建相應的對象,此時就需要一系列判斷
1 char pStr[20] = {0}; 2 cin >> pStr; 3 if(strcmp(pStr,"AAAA") == 0) 4 AAAA *p = new AAAA; 5 if(strcmp(pStr,"BBBB") == 0) 6 BBBB *p = new BBBB; 7 if(strcmp(pStr,"DDDD") == 0) 8 DDDD *p = new DDDD;
這個時候就會出現我遇到的情況,代碼繁雜,降低復用性,首先修改的就是創建對象,據說好的程序員不會寫出來毀滅地球的代碼,而是寫一個毀滅行星的函數,把地球當作參數傳進去
1 void CreateObjectAAAA() 2 { 3 AAAA *p = new AAAA; 4 } 5 void CreateObjectBBBB() 6 { 7 BBBB *p = new BBBB; 8 } 9 void CreateObjectDDDD() 10 { 11 DDDD *p = new DDDD; 12 } 13 int main() 14 { 15 char pStr[20] = {0}; 16 cin >> pStr; 17 if(strcmp(pStr,"AAAA") == 0) 18 CreateObjectAAAA(); 19 if(strcmp(pStr,"BBBB") == 0) 20 CreateObjectBBBB(); 21 if(strcmp(pStr,"DDDD") == 0) 22 CreateObjectDDDD();
然后如何能動態創建呢,可以想到鏈表可以實現動態的創建,但是創建對象無法用鏈表來表示,但可以將字符串,創建對象的函數指針打包成一個結點,只要輸入字符串,就可以遍歷鏈表實現創建了
1 struct Node 2 { 3 char pStr[20]; 4 void (*pfnCreateObject)(); 5 Node* pNext; 6 };
但現在問題是如何實現普適性,比如直接在類里貼一個宏,之后不用再創建對象了
首先是統一結點,由於在創建對象之后需要使用對象,創建對象函數return的值也都不一樣,這樣的話,結點里的函數指針的類型也不一樣了,統一結點的方法就是利用父類指針指向子類對象,為這些類創建一個父類,這個函數指針直接定義為父類即可
1 struct Node 2 { 3 char pStr[20]; 4 COObject* (*pfnCreateObject)(); 5 Node* pNext; 6 }; 7 COObject* CreateObjectAAAA() 8 { 9 AAAA *p = new AAAA; 10 return p; 11 } 12 COObject* CreateObjectBBBB() 13 { 14 BBBB *p = new BBBB; 15 return p; 16 } 17 COObject* CreateObjectDDDD() 18 { 19 DDDD *p = new DDDD; 20 return p; 21 }
接下來用宏代替每個類里的什么東西呢,換句話說哪些東西需要寫到類內呢?
結構體,遍歷匹配,放在父類中
1 #pragma once 2 class COObject; 3 struct Node 4 { 5 char pStr[20]; 6 COObject* (*pfnCreateObject)(); 7 Node* pNext; 8 }; 9 class COObject 10 { 11 public: 12 COObject(void); 13 virtual ~COObject(void); 14 public: 15 COObject *Create(const char *pszClassName); 16 };
1 #include "OObject.h" 2 #include<string.h> 3 4 COObject::COObject(void) 5 { 6 } 7 8 9 COObject::~COObject(void) 10 { 11 } 12 COObject *COObject::Create(const char *pszClassName) 13 { 14 Node *pTemp = 0; 15 while(pTemp) 16 { 17 if(strcmp(pTemp->pStr,pszClassName) == 0) 18 { 19 return pTemp->pfnCreateObject(); 20 } 21 pTemp = pTemp->pNext; 22 } 23 return 0; 24 }
而每一個子類中則放入創建結點,創建對象函數,其中有一點尤為注意,因為此時並未創建對象,所以這里的成員函數都是靜態成員
1 #pragma once 2 #include"OObject.h" 3 class AAAA : public COObject 4 { 5 public: 6 AAAA(void); 7 ~AAAA(void); 8 public: 9 static Node node; 10 static COObject*CreateObject(); 11 };
1 #include "AAAA.h" 2 Node AAAA::node = {"AAAA",0,&AAAA::CreateObject}; 3 COObject*AAAA::CreateObject() 4 { 5 return new AAAA; 6 } 7 8 AAAA::AAAA(void) 9 { 10 } 11 12 13 AAAA::~AAAA(void) 14 { 15 }
每個類都如此,但是當我實際操作的時候,程序卻崩了,調試后發現,在遍歷中,我每加一個結點就得修改一此頭結點,那我寫上面這些的意義就不存在了,都是添加還不如一大堆if看起來邏輯清晰呢,最后通過一個辦法可以解決,由於在函數之外不允許調用函數,除了一個,那就是構造函數,我在父類中又定義了一個專門添加的類,在這個類的構造里我把添加的結點傳進去,進行頭結點的更替,在遍歷中始終從頭節點開始遍歷。那么在以后的編程中,如果我不知道何時該創建對象的話,在類的頭文件和實現中就可以分別貼上這兩個宏,再繼承一個COObject的接口類即可。
1 #define DECLEAR_DYNCREATE()\ 2 static Node node;\ 3 static COObject*CreateObject();
1 #define IMPLEMENT_DYNCREATE(ThisClass)\ 2 Node ThisClass::node = {#ThisClass,0,&ThisClass::CreateObject};\ 3 InitObject init##ThisClass(&ThisClass::node);\ 4 COObject* ThisClass::CreateObject()\ 5 {\ 6 return new ThisClass;\ 7 }
2019-06-23 14:17:33 編程小菜鳥自我反思,大家可以留下自己的意見和建議,謝謝!!!