前言:同上文一樣,本文源於對另一位朋友的問題的解答
(參見帖子http://***munity.csdn.***/expert/topic/3202/3202729.xml?temp=5.602664e-02)
c++不是動態語言,所以沒法從語言機制上實現類的動態建立,但這樣的需求卻有可能存在,乙個類似的例子便是mfc中cwnd類的create方法,其第乙個引數為window class的名字,這就允許使用者通過class的名字來建立相應的視窗。
要想實現這一點,必須有乙個「管理中心」,用於登記類的名字,並且通過名字能夠呼叫某個方法來建立相應的類。結合類工廠的設計思想,這裡我們讓一套繼承體系中的基類作為「管理中心」,由它來維護所有派生類的必要資訊,包括類名和工廠函式,這二者必須建立起對映關係,map是不錯的選擇。定義了乙個派生類後,它就自動向基類進行註冊,可是如何實現自動呢?先看看程式吧:
// 為編寫方便,下面的**都位於.cpp檔案中
#ifdef _msc_ver
#pragma
warning(disable: 4786)
#endif
#include
#include
using
namespace
std;
class base
protected:
typedef base* (*classgen)();
// 宣告函式指標
static
void
register(const
char* class_name, classgen class_gen)
// 註冊函式
public:
static base* create(const
char* class_name)
// 工廠函式
return null; }
protected:
static mapchar*, classgen> class_set;
// 儲存子類資訊};
mapchar*, base::classgen> base::class_set;
// 靜態成員變數定義
class derived :
public base
} };
static base* create()
// 工廠函式
public:
virtual
void print()
// 測試用 };
static derived::derivedregister derived_for_registering;
// 沒有其它機制能夠保證在全域性空間呼叫註冊函式,
// 不得已,定義乙個全域性變數來完成這項光榮的任務,看起來有點齷齪
int main()
上面這樣實現,有的朋友可能覺得使用起來很麻煩,實際上我們用巨集定義來改造一下就會非常漂亮,**呆會兒就會看到。還是說說自動註冊功能吧,首先,為什麼要實現自動註冊呢?這是為了最大程度上隱藏實現,實際上採用手動註冊也可以,只不過我們得在主函式裡一一呼叫每個類的註冊函式。那我們是如何實現自動註冊的呢?方法是將註冊**放到乙個輔助類的建構函式中,然後定義乙個該類的靜態全域性變數,這樣建構函式便被呼叫了,:),缺點是多了乙個額外的物件,除了用於註冊外,它什麼用也沒有(最初我沒有採用輔助類,而是直接在派生類的建構函式中註冊,然後定義派生類的全域性變數,這樣明顯會浪費空間,採用輔助類便將額外開銷降低到了最小)。
下面讓我們瞧瞧用巨集改造後的模樣:
#ifdef _msc_ver
#pragma
warning(disable: 4786)
#endif
#include
#include
using
namespace
std;
// 用於宣告具有動態建立功能的基類
#define declare_dyncrt_base(base) /
public: /
typedef base* (*classgen)(); /
static
void
register(const
char* class_name, classgen class_gen) / /
public: /
static base* create(const
char* class_name) / /
return null; /
} /
protected: /
static mapchar*, classgen> class_set;
// 用於實現基類
#define implement_dyncrt_base(base) /
mapchar*, base::classgen> base::class_set;
// 用於宣告乙個能夠被動態建立的類
#define declare_dyncrt_class(derived, base) /
public: /
struct derived##register / /
} /
}; /
static base* create() /
// 用於實現乙個能夠被動態建立的類
#define implement_dyncrt_class(derived) /
static derived::derived##register derived##_for_registering;
// 測試
class base
};
implement_dyncrt_base(base)
// 實現動態基類
implement_dyncrt_class(base)
// 實現動態類
class derived :
public base
};
implement_dyncrt_class(derived)
// 實現動態類
int main()
上面的巨集定義可以重複利用(是不是有點似曾相識,是的,mfc中在對序列化和動態建立等支援時用到了類似的巨集),在使用的時候,只需簡單的使用這四個巨集,即可實現動態建立,感覺還不錯吧,不過提醒一點,其中的兩個implement巨集都應該放在.cpp檔案中。
這種方法還是存在一些缺點的,不過本文主要是提供一種思路,可以根據具體的情況再作相應變動。
(freefalcon於2004.09.19)
C 實現反射 根據類名動態建立物件
和網上大多數實現一樣,這裡也是採用工廠方法來實現物件的動態建立。大致原理為,建立乙個單例工廠類,其中維護乙個map 類名 物件建立函式 建立物件時,傳入類名,然後根據此類名查詢出建立函式,最後建立物件。採用這種方式,有乙個關鍵問題,便是在工廠中註冊類名。我們的辦法是針對於每乙個類 class 定義乙...
Flex動態建立類物件
自actionscript 3開始,eval函式就被取消了,這樣就不能像原來那樣利用字串動態的建立物件了,但利用函式flash.utils.getdefinitionbyname仍可以根據型別名稱動態地建立類物件例項,下面看乙個例子 輸出結果 dynamicobject is created dyn...
Flex動態建立類物件
flex動態建立類物件 2010年08月07日 之所以會出錯,是因為在flex編譯程式時會自行刪除一些未使用的,這時在動態建立物件時就會因缺失物件的型別而建立失敗。之前的 之所以執行成功,是因為型別dynamicobject在 中顯示地被使用,所以型別資訊dynamicobject在編譯時不會被刪除...