2010-01-11 78 views
2

我有一個類層次結構,例如:C++設計問題

Entity 
    Stationary 
     Tree 
    Creature 
     Bear 
     Crow 

而且我有一個世界和一個播放器。當玩家碰到東西時,它會調用handleCollision(Entity * entity),然後根據不同情況發生的事情;如果玩家撞到樹上,則在玩家攻擊時沒有任何反應,如果它是熊。問題是我不確定如何以好的方式區分案例。

想到的一個想法是這樣的。 Player :: handleCollision(Entity *)調用Entity-> handleCollisionHelper(Player &)。這是一個虛擬函數,它在Tree中什麼也不做,在Creature(它應該攻擊所有生物)時調用Player.handleCollisionCreature(this),然後將攻擊代碼放置在handleCollisionCreature中。有沒有更好的方法來做到這一點而不使用RTTI(typeid等)?

+1

你在做什麼很好。它被稱爲雙重派遣,在這種情況下是一種常見模式。 – 2010-01-11 11:02:05

+0

我不知道爲什麼大家都認爲這是雙發。我們只有一個具有變量類型的對象(與(實體)碰撞的對象)。等式的另一端有一個固定類型的對象(一個Player)。因此,這是一次調度,因此虛擬功能是實現解決方案的完美方式。 – 2010-01-11 15:33:17

+0

Martin,僅使用單個分派來實現這一點的方法需要在實體基類(和派生類)中使用諸如「CollidedWithPlayer()」的方法。這是可能的,但相當有限 - 當你希望突然開始支持與其他對象的碰撞時會發生什麼?或者當玩家也是基類,並且可能有不同的具有特定碰撞的子類? 取決於上下文,它可能是一個可行的解決方案。可能不在這裏描述的上下文中。 – Hexagon 2010-01-12 05:50:14

回答

3

虛擬方法(Player & player)arg看起來非常好OO設計。正如你所說,你可以添加某種形式的類型或使用RTTI,並通過排列切換案例,但這將是非常C風格的功能風格。只要你沒有每秒進行數千次虛擬呼叫,你應該沒問題。

2

只是爲官方名稱提供參考 - 這個問題被稱爲Double Dispatch(您需要根據兩個對象的類型同時決定做什麼)。

查看維基百科文章http://en.wikipedia.org/wiki/Double_dispatch的一些細節和建議的解決方案。

+0

他爲什麼需要雙重派遣。我只看到一個可能有不同類型的對象(被擊中的對象)。另一方面,擊球對象始終是球員。因此,這是通過虛擬功能實現的單個分派。 – 2010-01-11 15:29:46

0

而是觸發實體*的,你爲什麼不有這樣的事情:

handleCollision(Stationary& stationary) 
{ 
    // Nothing to do yet? 
} 

handleCollision(Creature& creature) 
{ 
    creature.StartCombat(this); 
} 

,並刪除實體*功能。這將確保只有生物纔會開始戰鬥(將StartComabt功能添加到你的生物類)。或者,你可以有一個戰鬥類:

handleCollision(Creature& creature) 
{ 
    Combat::Begin(this, creature); 
} 
0

我想你在找什麼叫「double dispatch」或「multimethods」。

根據多個對象的動態類型調用不同的函數並不是C++的內置功能,但有許多衆所周知的技術可以推出自己的技術。您建議的級聯呼叫可能是最常見的呼叫。