2012-02-07 71 views
1

我已經得到了遊戲對象的層次結構:對象類型檢測層次

class GameObject { 
public: 
    virtual void update(float dt) = 0; 
    virtual void draw() = 0; 
}; 
class Building : public GameObject {} 
class Sawmill : public Building {} 
class Human : public GameObject {} 

等。所有對象都由遊戲管理(不是GameObject的子類)。遊戲將所有對象存儲在std :: vector < GameObject * >中,併成功調用了更新和繪製等虛擬方法,這一切都很好。但有時我需要檢測我正在處理的GameObject的類型。對於這種情況,我們提出了一個解決方案:GameObject具有GameObject類型的枚舉,並且每個GameObject子類從該枚舉返回自己的值。

class GameObject { 
public: 
    enum GOType 
    { 
     GOGameObject, 
     GOBuilding, 
     GOSawmill, 
     GOHuman, 
     ... 
    } 
    static GOType Type() { return GOGameObject; } 
    virtual GOType getType() const { return GameObject::Type(); } 
}; 

class Building : public GameObject { 
public: 
    static GOType Type() { return GOBuilding; } 
    virtual GOType getType() const { return Building::Type(); } 
}; 

所以,遊戲對象的每個子類都有它返回從枚舉GOType值「靜態GOType類型()」方法的自己的版本。它重載了虛擬方法「GOType getType()const」,它只是調用它自己的類方法Type()。任何地方比賽,我可以檢查對象我有一個指向是,例如,一個大廈:

if (obj && obj->getType() == Building::Type()) { 
    // then do stuff 
} 

要清楚 - 這個解決方案工作正常,並已證明是可擴展的,非常有效的(在我們提出的第一個解決方案是在getType()中返回字符串並對它們進行比較;它們的速度很慢)。

唯一的缺點我看到的是,我必須在遊戲對象每次添加一個新的遊戲對象的子類時間延長GOType。現在它包含大約一百種類型,它看起來並不美觀(我在這裏是一個完美主義者:)

所以,我的問題是:是否有任何其他解決方案的問題是有效的這一個,但沒有必要在GameObject中擴展GOType?

+0

您可以使用typeid的 – 2012-02-07 13:52:40

+0

什麼去'//然後做stuff'?根據這一點,你可以得到更好的解決方案。 (http://www.antiifcampaign.com/) – 2012-02-07 13:55:38

+2

「有時我需要檢測我正在處理的遊戲對象的類型」 - 這可能是您設計中的錯誤。如果你經常檢查類型,那麼儘管使用類,你仍然不是以面向對象的方式進行編程。對於不同類型的反應,請使用[double dispatch](http://en.wikipedia.org/wiki/Double_dispatch)。 – 2012-02-07 13:57:18

回答

1

您可以使用dynamic_cast

if (dynamic_cast<Building*>(obj)) 
{ 
    // then do stuff 
} 

將沒有需要一種enumgetType()方法。

+0

這將無法正常工作,雖然RTTI啓用嗎? – Firedragon 2012-02-07 13:59:51

+0

@Firedragon不,它不會。 – 2012-02-07 14:00:22

+0

@Firedragon:好像任何人都愚蠢到足以編譯缺少核心語言功能的代碼。 – Puppy 2012-02-07 14:29:09

0

我的直覺是,是,你需要知道他們鍵入的內容是在運行時則可能存在的設計問題。如果你在對象上調用你的「做東西」,那麼使用虛函數和多態將意味着你不需要知道對象是什麼。

話雖如此,如果你啓用RTTI那麼這似乎是一種方法來確定是什麼類型的對象在運行時無需添加它們輸入到基類。

typeid可用於在運行時確定的類型。

+0

由於某些歷史原因,我們不在項目中使用RTTI – dimayak 2012-02-07 13:57:03

+0

@dimayak沒有RTTI,您不能使用'dynamic_cast'或'typeid '所以在運行時檢測,我懷疑是否需要你在代碼中使用它的方式(除非比我更懂得知道的人可以提供一種方式),但正如我和其他人所說的,有一些方法可以使用多態,所以你不需要要知道這是什麼類型 – Firedragon 2012-02-07 14:03:24

2

爲什麼不模仿您的drawupdate函數,因此您可以傳入任何T,它將執行您所需的任何操作。如果您需要針對特定​​的T有不同的行爲,您可以專注於此。

只是一個建議。

+0

沒有得到你的意思。你能提供一些代碼來說明你的意思嗎? – dimayak 2012-02-07 14:25:41