2011-12-13 90 views
1

假設我有以下繼承樹:多繼承,還是其他?

SDLBullet inherits from Bullet inherits from Entity 
EnemyBullet inherits form Bullet inherits from Entity 

現在我需要一個新的類,SDLEnemyBullet,這就需要平局在SDLBullet實現,碰撞在EnemyBullet實現。我將如何做到這一點?這是用多重繼承來解決的嗎?如果沒有,請隨時編輯我的問題和標題。如果是這樣,我將如何實施這樣的事情?

下面的某些代碼示例:

class Entity { 
    bool collision(Entity) = 0; 
    void draw() = 0; 
} 

class Bullet : Entity { 
    bool collision(Entity) {/*some implementation*/}; 
    void draw() {/*draw me*/}; 
} 

class SDLBullet : Bullet { 
    void draw() {/*draw me using SDL*/}; 
} 

class EnemyBullet : Bullet { 
    bool collision(Entity) {/*if Entity is a fellow enemy, don't collide*/}; 
} 

class SDLEnemyBullet : ????? { 
    /*I need SDLBullet::draw() here*/ 
    /*I need EnemyBullet::collision(Entity) here*/ 
    /*I certainly do not want EnemyBullet::draw nor SDLBullet::collision here*/ 
} 

任何幫助,非常感謝!

(BTW:。這是一所學校的項目,像這樣的繼承樹有人建議我們沒有一個是從做不同的,更好的那阻止我們爲什麼我問的問題)

+0

'Bulne'上的'EnemyBullet'有什麼特別的區別?是否有更多的實施,而不僅僅是碰撞檢測?因爲如果是這樣的話,你可以移除這個類,只需檢查一下Bullet來確定源(不管是否敵人)並忽略某些檢查,這樣你就不會爲敵人重複Bullet的每個子類。 – Grambot

+0

如果你只是在尋找語法,它是'SDLEnemyBullet類:SDLBullet,EnemyBullet {/ * ... * /};',或者可能用訪問說明符(「'public'」)來裝飾。不過,不要這樣做,因爲它會創建兩個Bullet子對象的副本。 –

+0

我想讓子彈與所有物體相撞,而不是與敵人發生碰撞的敵方子彈相撞。我也計劃製作一個PlayerBullet。我不知道我是否仍然需要普通的Bullet,但我打算保持靈活性,我可能有一天需要它。 (另外,現在一切都是正常的SDLBullet,所以如果玩家趕上他的子彈,他就會死亡,如果敵人與另一個敵人子彈相撞,它就會死亡,後者最讓我困擾) – Mats

回答

3

教科書解決方案涉及多重和虛擬繼承。

 
class SDLBullet : public virtual Bullet { 
    void draw() {/*draw me using SDL*/}; 
}; 

class EnemyBullet : public virtual Bullet { 
    bool collision(Entity) {/*if Entity is a fellow enemy, don't collide*/}; 
}; 

class SDLEnemyBullet : public SDLBullet, public EnemyBullet { 
    // just one Bullet subobject here 
}; 
+0

如果我這樣實現它,SDLBullet和EnemyBullet將不再可用作獨立類,它們不會變得抽象嗎? SDLBullet需要它自己的碰撞方法,因爲它也是一個可能出現在遊戲中的實體。 (**編輯:**我現在看到,SDLBullet仍然具有Entity的實現,我還可以聲明'Entity * e = new SDLBullet;'?) – Mats

+0

我只添加了'virtual'(和'public')。這不會將具體類改爲抽象類,反之亦然,所以如果你之前可以聲明一個'SDLBullet',你仍然可以這樣做。我也建議閱讀虛擬繼承; [維基百科文章](http://en.wikipedia.org/wiki/Virtual_inheritance)將是一個好的開始。 –

2

通常情況下,碰撞的東西是使用多次調度完成的,或者是使用訪問者模式的C++中沒有這個功能的東西。

你爲什麼不有這樣的而不是層級?

class Entity; 

class Bullet : public Entity 
{ 
public: 
virtual draw(); 
} 

class FriendlyBullet : public Bullet 
{ 
public: 
bool collide(EnnemyBullet*); 
bool collide(FriendlyBullet*); 
} 
class EnnemyBullet : public Bullet 
{ 
public: 
bool collide(EnnemyBullet*); 
bool collide(FriendlyBullet*); 
} 

這將工作太,並且不需要multidispatch或多重繼承

+0

訪客模式,我來看看! (雖然這不是我的問題的真正答案,但它可能是另一種方法。) – Mats

+0

對不起,我張貼得太快。添加了一些更好地回答你的問題的東西...我認爲;) – Dinaiz

+0

我真的需要多態性,我沒有你的代碼.. – Mats

2

你需要指定超類的逗號分隔的列表:

class SDLEnemyBullet : public SDLBullet, public EnemyBullet { 
    /*I need SDLBullet::draw() here*/ 
    /*I need EnemyBullet::collision(Entity) here*/ 
    /*I certainly do not want EnemyBullet::draw nor SDLBullet::collision here*/ 
} 

它看起來就像你做一個遊戲(發動機)。爲了避免像這樣的複雜繼承結構,需要對實體進行繼承,也就是擁有一個包含用於渲染的單獨「組件」對象的實體對象。這樣,您可以混合和匹配您喜歡的組件,而無需爆炸類與超類的所有不同組合。

下面是關於這個問題的好文章:http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

+0

鏈接不同的組件將使用多重繼承? – Mats

+0

不,它消除了對多重繼承的需求。在你的情況下,我不會推薦使用多重繼承。 –

+0

我會進一步研究組成,謝謝你的提示。 – Mats

1

Prefer composition over inheritance

你不需要繼承來的東西,不是像相關相結合。爲遊戲邏輯,物理,聲音,輸入,圖形(可以使用繼承)組成基本對象(實體?),並組合那些只有一組所述對象的GameObject。

一些漂亮的交叉鏈接是有用的,因爲它們都將共享一個Frame或Transform,但是可以在創建期間通過迭代所有其他對象並使用dynamic_cast ...(如果您不需要依賴按初始化順序)。

但是確實沒有必要用繼承來構建它。它不適合你的用例。 (雖然虛擬繼承是有用的,但使用繼承來強制不同的東西變成相同的東西並不是一件好事,也就是使所有東西都變成一個東西,而不是由不同的部分組成(渲染,損壞,聲音等等)。 ..)。

閱讀thisthis欲瞭解更多信息,或只是點擊標題爲谷歌它。 :)

+0

我會進一步探討這一點,但繼承方式是它向我們提出的方式(這是一個學校項目)。沒有人阻止我們以另一種方式去做,也許更好的方式。這就是我問這個問題的原因。 – Mats

+0

@Mats:好的。對於學校來說,嘗試這樣做是很好的。但是我見過並且合作過的所有嚴肅/現代的遊戲引擎都試圖避免繼承,因爲它可以很容易地將事物的不同方面結合起來。我建議你嘗試一起構建一個小的基於合成的框架,以瞭解它是如何工作的。 – Macke