2010-10-29 62 views
1

我正在做一些似乎可以改進的東西,但我沒有足夠的技能來改進它。你能幫我嗎?更好的方法來做到這一點?

考慮:

vector<Base*> stuff; 
const vector<MetaData>& metaDataContainer = Config.getMetaData(); 

for(vector<MetaData>::const_iterator i = metaDataContainer.begin(), end = metaDataContainer.end(); i != end; ++i) 
{ 
    Base* pCurrent = buildDerivedType(*i); 
    stuff.push_back(pCurrent); 
} 

Base* buildDerivedType(MetaData meta) 
{ 
    Base* pRetval = NULL; 

    switch(meta) 
    { 
    case MetaData::A: 
    pRetval = new Alpha(); 
    break; 

    case MetaData::B: 
    pRetval = new Beta(); 
    break; 

    //so on so forth 
    }; 
    return pRetval; 
} 

我覺得switch語句是不好的,因爲在編譯時所有的枚舉值是已知的,所以理論上我們已經知道是什麼類型需要進入矢量的東西。但我們在運行時會這樣做。

爲此編寫代碼生成器的缺點,有沒有更好的方法?

+1

「在編譯時所有的枚舉值被稱爲」 - 你的意思是,你知道metaDataContainer'的'的內容?它看起來並不那樣。而'switch'是實現工廠模式的體面方式。 – aschepler 2010-10-29 17:13:52

+0

你是對的,我不知道容器包含什麼,但我知道它可能包含的所有可能的值。所以如果MetaData與A,B,C聯繫在一起,我知道那些是可能性,但是,我可能只會得到A和C. – anio 2010-10-29 17:16:31

回答

3

不是。但是,您可以用factory type抽取大部分樣板並使用boost::ptr_vector或智能指針容器以智能方式管理資源。 (See comments關於智能容器與智能指針的啞容器之間的選擇)。

3

那麼,您可以預先分配一個映射元 - >函數,它可以創建所需的派生類型。

typedef Base* ((*DerivedTypeCreator)()); 
map <MetaData, DerivedTypeCreator> derivedTypeBuilders; 

// ... 
derivedTypeBuilders[MetaData::A] = &CreateAlpha; 
derivedTypeBuilders[MetaData::B] = &CreateBeta; 

Base* CreateAlpha() 
{ 
    return new Alpha(); 
} 

Base* CreateBeta() 
{ 
    return new Beta(); 
} 

// ... 
for(vector<MetaData>::const_iterator i = metaDataContainer.begin(), 
     end = metaDataContainer.end(); 
    i != end; ++i) 
{ 
    stuff.push_back((*(derivedTypeBuilders[*i]))()); 
} 

請不要忘記考慮當元的價值是不是在地圖上!

因爲如果您的元數據值是小數目的特定情況下,你甚至可以消除運行時開銷:

DerivedTypeCreator[] derivedTypeBuilders = { 
    &CreateAlpha, // Metadata::A == 0 
    &CreateBeta // Metadata::B == 1 
}; 

// ... 
stuff.push_back((*(derivedTypeBuilders[(int)*i]))()); 

- 但這種方法也許是太低級,而且容易出錯。 (希望C ​​++語法允許這樣的初始化。)

0

您正在詢問工廠模式。你可以谷歌的。要儘可能多地進入編譯時(w.r.t.運行時),您可能需要使用模板添加搜索條件

但是,由於您的元數據向量''包含運行時的信息,因此您需要一些動態的。 enum不是一個壞主意 - 看這裏,例如:http://www.daniweb.com/forums/thread18399.html。 還請注意typedef InstantiatorMap::value_type InstantiatorMapEntryType末尾的位。使用工廠時將''枚舉''映射到''成員函數指針''。

+1

啊,如果可能的話,你可能想要更新你的標題。 – towi 2010-10-29 17:18:46

2
template<class T> Base* Creator() { return new T; } 
typedef Base* (*CreateType)(); 
typedef std::pair<const MetaData, CreateType> cpair; 

cpair mapper [] = 
{ 
    cpair(MetaA, Creator<A>), 
    cpair(MetaB, Creator<B>), 
}; 

std::map<MetaData, CreateType> typemap(&mapper[0], &mapper[sizeof(mapper)]); 

void foo(MetaData m) 
{ 
    Base* a = typemap[m](); 
} 
+0

地圖構造函數的不錯用法。 – Vlad 2010-10-31 12:30:16

相關問題