2014-06-08 84 views
3

我有基類產品用來存儲一些數據,並通過存取授予其訪問權限,如:所有派生類通用接口

class Item{ 
    (...) 
public: 
    int get_value(); 
    double get_weight(); 
    ItemMaterial get_material(); 
    (...) 
} 

那麼我就派生類,如武器,防具裏面加一些額外的數據:

class Weapon : public Item { 
(...) 
public: 
    int get_dmg(); 
    (...) 
} 

我這些物品存放在一些容器:

std::vector<Item*> inventory; 

這裏來的接口問題 - 如何訪問派生類數據?我想,並得到3種思路:

1.分離的接口

每個派生類增加它的數據,如在上面示出,然後用dynamic_cast的:

Item *item = new Weapon; 
int dmg = dynamic_cast<Weapon*>(item)->get_dmg(); 

2 。通用接口類

與所有訪問器構成一個接口類:

ItemInterface{ 
public: 
    virtual int get_value() = 0;  //Item interface 
    virtual double get_weight() = 0; 
    (..) 
    virtual int get_dmg() = 0;  //Weapon interface 
    (...) 
} 

然後是這樣的:

Item : public ItemInterface{ (...) } 

Weapon : public Item { (...) } 

終於可以訪問數據:

Item *item = new Weapon; 
int dmg = item->get_dmg(); 

3.組合使用模板和枚舉

這種想法也許有點不可思議,但:-):

實現與所有項目數據枚舉:

enum class ItemData{ 
    Value, 
    Weight, 
    Material, //Item data 
    (...) 
    Damage, //Weapon data 
    (...) 
    Defense, //armor data etc. 
    (...) 
    Null 
} 

,並在基類中的一些模板函數是這樣的:

template<typename T> 
T get_data(ItemData data){ 
    switch(data){ 
    case ItemData::Value: return _value; break; 
    case ItemData::Damage: return _dmg; break; 
    (...) 
    } 
} 

和訪問數據,如:

Item *item = new Weapon; 
ind dmg = item->get_data<int>(ItemData::Damage); 

===

您認爲應該怎麼做?我會感激任何意見!

問候。

+0

如果需要訪問特定derived-類的東西,你爲什麼使用指針到基地?換句話說,給定一個任意的Item *',你怎麼知道它適合轉換爲'武器*'來得到武器特定的東西? –

+0

沒有好 - 如果您無法爲數據建模,請使用dynamic_cast –

+0

因爲,例如,對象Creature包含庫存(如示例中所示),並且我想將所有基於項目的類保存在此容器中。如果它合適? dynamic_cast給我這個信息。在其他情況下,我想我應該,例如,在基礎類中添加一些數據字段,以提供此信息。 –

回答

2

你的第二個和第三個選項顯然是不是要走的路 - 每當你添加一個新類型的項目,你也將不得不改變基類或枚舉 - 這絕對不是你想要的東西如果您需要在代碼中使用任何基本的可維護性。

這裏來與接口的問題 - 如何獲得訪問派生類數據

首先你要想到「你的代碼中會做到這一點」?大部分處理整個inventory的代碼只能使用Item*的內容,僅使用Item類中的函數。

如果你有代碼specificially處理Weapon對象,其中Weapon對象被創建(插入inventory)的地方,也可能他們的

std::vector<Weapon*> weapons; 
形式添加到另一個變量,也許武器清單

或類Warrior類或類似的成員變量Weapon*(但要小心,你現在將有兩個指向相同的對象,所以你必須考慮所有權)。因此,僅處理武器的代碼(例如Warrior的成員函數)不訪問inventory以獲取Weapon對象,它將始終直接使用Weapon*。如果由於某些原因,您必須編寫一些代碼來清點庫存中的所有武器,然後編寫一個函數,使用dynamic_cast(或者更好的是:使其成爲一個迭代函數)提取所有對象Weapon, ,並在需要訪問所有武器時重新使用此功能。所以你不要把你的代碼與動態演員混爲一談,而只是把它放在一個地方。

編輯:另一種選擇(避免朝代演員)使用訪客模式,請參閱this post。但我真的不喜歡這篇文章的答案,在呈現的形式中,它意味着循環依賴「Base - > Visitor - > Derived - > Base」,這是恕我直言的一個糟糕的設計。

1
ValueType Weapon::getProprtyValue(PropertyType id) { 
    switch(id) { 
     case kWeaponProperty01: return m_weaponProperty01; 
     ... 
     default: return Item::getPropertyValue(id); 
    } 
} 

可以做出某種通用的訪問方法,雖然它有一定的侷限性,它可能是很方便,特別是在內容編輯,系列化等的情況下

+0

這就像一個EAV模型http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model,它避免了所有的繼承需求,這使得問題變得毫無意義。這*可以在某些特定情況下成爲解決方案。但是我不懷疑OP的給定繼承樹的正確性,這個問題對於給定指向基類的元素向量的所有類模型都是有效的。 –