2011-06-11 39 views
7

我想使用繼承有不同的地方在層次結構中它屬於不同的方式處理的物體C++重載決議

similar to this C# question

假設你建立Shape對象的層次結構,如:

class Shape {} ; 
class Sphere : public Shape {} ; 
class Triangle : public Shape {} ; ... 

你再裝備一個雷類等的方法:

class Ray 
{ 
    Intersection intersects(const Sphere * s) ; 
    Intersection intersects(const Triangle * t) ; 
}; 

您存儲各種類型的各類形狀*的數組,並調用

vector<Shape*> shapes ; ... 
//foreach shape.. 
Intersection int = ray.intersects(shapes[ i ]) 

但你的編譯器錯誤

錯誤C2664:「交集雷::相交(常量球*)常量」:不能將參數1從'Shape * const'轉換爲'const Sphere *'

你做錯了什麼?

是做其他周圍方式的必由之路,與

class Shape 
{ 
    virtual Intersection intersects(const Ray* ray)=0 ; 
} ; 

然後每一類覆蓋相交?然後撥打電話

//foreach shape.. 
Intersection int = shapes[i]->intersects(ray) ; 

你可以做到這一點,我的第一種方式顯示或從不?

+1

我認爲這是[multiple(double)dispatch](http://en.wikipedia.org/wiki/Multiple_dispatch)。 C++本身沒有它。 – 2011-06-11 16:08:53

+0

[繼承並不總是對的。](http://en.wikipedia。org/wiki/Circle-ellipse_problem) – 2011-06-11 16:12:42

回答

4

你必須以相反的方式去做。重載解析發生在編譯時,當你調用它的類型是Shape*

4

不,你不能這樣做的第一種方式。 C++中的重載分辨率基於靜態函數參數類型。它在編譯時解決。在你的例子中,靜態類型是Shape *,你的班級裏沒有任何功能可以接受Shape *(因此是錯誤)。編譯器不關心你的指針在運行時可能實際指向Sphere

要實現你想實現你有什麼「道」的調用都通過依靠動態類型的對象,即通過虛擬函數調用,這是你在你的第二個例子做什麼設施。

您的第二個示例稍微簡化了一點,因爲涉及的其中一個對象的類型在編譯時已知(Ray)。在更復雜的情況下,涉及「交集」的兩個對象都可以是動態類型的。如果你喜歡處理這樣的事情,你可以使用所謂的「雙派」技術(搜索它)。

0

可能是您可以使用RTTI信息來獲得此信息。我沒有這樣做,但它可能是可能的。

class Ray 
{ 
    Intersection intersects(const Sphere * s) ; 
    Intersection intersects(const Triangle * t) ; 
    Intersection intersects(const Shape * s) { 
     //act on RTTI info, or 
     //use dynamic_cast to other types and check if the result is NULL or not 
    } 
}; 
+0

是的,我知道'typeid()',但我當然想避免使用 – bobobobo 2011-06-11 16:11:07

+1

那麼答案几乎肯定不是。 – 2011-06-11 16:12:21