2012-11-05 83 views
3

我有以下類別:虛擬方法和參數查找

Collider (abstract based class) 
BoxCollider 
MeshCollider 
SphereCollider 

從撞機最後3繼承。

用例是每個對撞機都應該可以檢查它是否與任何其他碰撞對象碰撞。

我想象中的電話應該是在對撞機類,看起來像:

void Collider::checkCollisionsWithOtherColliders() 
{ 
for(std::vector<Collider*>::iterator it ....) 
{ 
if(this->isCollidingWith(*it){...} 
} 
} 

現在到了我應該如何定義isCollidingWith

我想我需要把它定義爲每對中的問題的碰撞體,這意味着每個碰撞體類型都應該爲每種類型的碰撞體使用這種方法的版本作爲參數,例如在SphereCollider:

class SphereCollider : public Collider 
{ 

bool isCollidingWith(SphereCollider* c){..} 
bool isCollidingWith(BoxCollider* c){..} 
bool isCollidingWith(MeshCollider* c){..} 

}; 

要確保這些方法是通對撞機基類訪問,我需要定義

class Collider 
{ 
virtual bool isCollidingWith(SphereCollider* c){..} 
virtual bool isCollidingWith(BoxCollider* c){..} 
.. and so on 
}; 

而且,由於呼叫this->isCollidingWith(*it)只需要一個指向撞機和NOT一個派生類,我希望列出的那些虛擬類的適當方法是在運行時自動獲取的。但是,這似乎並非如此:因爲參數只是Collider,它只用Collider *參數尋找一個方法。

我能想到的唯一的解決辦法是在對撞機定義:

bool isCollidingWith(Collider* collider) 
{ 
if (0 != dynamic_cast<SphereCollider*>(collider)) 
return isCollidingWith(dynamic_cast<SphereCollider*>(collider)); 
else if (0 != dynamic_cast<BoxCollider*>(collider)) 
return isCollidingWith(dynamic_cast<BoxCollider*>(collider)); 
else if ... 
} 

這是不是真的優雅。有沒有其他(適當的)方式來處理這種情況? 謝謝!

+0

當只有3種類型的關係時,您似乎會定義9個isCollidingWith()方法。 – imreal

+0

我不確定。實際上有一半的案例會重複,並且可以進行優化。但區分盒子/球體和盒子/盒子的碰撞會很有趣 – iseeall

+0

這是[Double Dispatch](http://en.wikipedia。org/wiki/Double_dispatch)問題 –

回答

4

這是double dispatch的情況。這裏不會詳細說明它,因爲它已經被廣泛使用,並且即使維基百科頁面過時了,使用該術語進行簡單的谷歌搜索也會產生好的結果。

+4

我至少會注意到,在C++中這通常是通過訪問者模式來完成的。 –

+0

@MarkB「上述問題可以通過模擬雙重調度來解決,例如使用訪問者模式。」 :) –

+1

大聲笑我想到的第一件事,當我看到「對撞機」這個詞是「雙派」。這是*經典的例子。 – Mehrdad

-1

由於您從Collider繼承了BoxCollider,MeshCollider和SphereCollider,因此不需要創建3種不同的方法來接受每個類的參數。這就是爲什麼OOP很棒。

您可以使用此:

class Collider 
{ 
    virtual bool isCollidingWith(Collider* c){..} 
}; 

class SphereCollider : public Collider 
{ 
    bool isCollidingWith(Collider* c){..} 
}; 

class BoxCollider : public Collider 
{ 
    bool isCollidingWith(Collider* c){..} 
}; 

class MeshCollider : public Collider 
{ 
    bool isCollidingWith(Collider* c){..} 
}; 

因爲該方法isCollidingWith是虛擬的,在運行時,由於多態性,正確的方法將被稱爲基於正在調用它的對象(並提供了繼承的類具有isCollidingWith(Collider * c)的實現,否則繼承的類也將變爲抽象類)。

例子:

Collider *c1 = new SphereCollider; 
Collider *c2 = new BoxCollider; 
Collider *c3 = new MeshCollider; 

// To check if Sphere is colliding with anything 
// This will go to the implementation in SphereCollider 
c1->isCollidingWith(c2); 
c1->isCollidingWith(c3); 

// To check if Box is colliding with anything 
// This will go to the implementation in BoxCollider 
c2->isCollidingWith(c1); 
c2->isCollidingWith(c3); 

// To check if Mesh is colliding with anything 
// This will go to the implementation in MeshCollider 
c3->isCollidingWith(c1); 
c3->isCollidingWith(c2); 

希望這有助於。

+1

這並不簡單。這是一個雙重調度問題,C++不能處理的東西。它可以用訪問者模式來模擬,有時你需要知道具體細節。例如,飛鏢總是會與「板甲」相撞,但如果射手幸運的話,一個小飛鏢可以直接穿過鍊甲護甲的孔。 –

+0

是的,在閱讀了評論之後,我意識到了這一點。現在閱讀雙重調度:)感謝您的反饋。 –