動態2 由類名建立物件

2021-03-31 08:56:29 字數 3254 閱讀 9456

前言:同上文一樣,本文源於對另一位朋友的問題的解答

(參見帖子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在編譯時不會被刪除...