2013-09-22 99 views
0

我的問題是:「我如何實現處理不同子類但能訪問來自兩個基類的方法的泛型函數?從另一個基類的多個繼承和通用訪問一個基類

我請你想象,我使用的結構如下假設的圖形庫:

class Shape 
{ 

// getters and setters are here 

private: 
    int m_BorderColor; 
    int m_FillColor; 
} 

class Square : public Shape 
{ 

} 

class Triangle : public Shape 
{ 

} 

class TextBox : public Shape 
{ 

} 

...等等。

該庫只允許將Shape基類的衍生物添加到其假設畫布中。在我的應用程序中,我希望在每個形狀和可能的其他屬性中都有一個文本框。

因此,我想有自己的基類,類似如下:

class MyBase 
{ 
public: 
    SetText (string text) { m_Text.Text = text; } 
    // other getters and setters here 

private: 
    TextBox m_Text; 
    int m_Id; 
} 

然後我就可以有「我」的形狀與文本框,如下所示:

class MySquare : public Square, public MyBase 
{ 

} 

我可以將MySquare添加到畫布,因爲它是Shape的子類。當用戶雙擊MySquare(或MyTriangle等)時,我想更改文本。但我只知道在運行時點擊哪個形狀。

以下顯然行不通,因爲的setText不是外形與我從庫中接收所述指針的構件,儘管(例如)是一種MyTriangle,被轉換爲外形:

// double click handler 
Shape* clicked_shape = clickEvent.GetShape(); 
clicked_shape->SetText("Foo"); 

我需要使用基類指針,因爲我不知道直到運行時纔得到哪個形狀對象。因此,雖然以下工作正常,但對我無用:

// double click handler 
Shape* clicked_shape = clickEvent.GetShape() 
((MyTriangle*)clicked_shape)->SetText("Foo") 

謝謝您對此問題的任何見解或更好的模式!

回答

1

這是怎麼回事?

MyBase * base = dynamic_cast<MyBase *>(clicked_shape); 
base->SetText("too"); 

您可能要檢查base被空,如果你得到的形狀實際上不是你的一個。

MyBase至少需要一個虛擬函數 - 析構函數會這樣做。

+0

dynamic_cast是最後的手段。在很多情況下,這表明設計不好。但有些時候這是不容易避免的。 – dmitri

+0

@dmitri我同意;我不經常使用它。但這正是它設計的問題類型。 –

+0

我嘗試了這樣的東西,但與static_cast。問題是,取決於哪個形狀是MyBase部分的偏移量不同,所以SetText訪問器崩潰。對不起,但dynamic_cast解決了這個問題嗎? – iwbnwif

0

Shape類是一個基類,因此它提供了一個可以被覆蓋的接口。例如。可能有draw()方法被稱爲繪製形狀。這將是一個很好的候選人,在您的新課程中用文本框覆蓋。例如:

class SquareWithText: public Square { 
    void draw() { 
    Square::draw(); // call base method 
    ... // add text box here 
} 

這裏沒有多重繼承,這爲您提供了一個更簡單的解決方案。 如果單一繼承不適合你,你可能會尋求更復雜的解決方案。

class ShapeWithTextBox : public Shape { 
    void draw() { 
    ... // add text box here 
    } 
} 

現在你會寫你的新類爲:

class MySquare : public Square, public ShapeWithTextBox 
{ 
    void draw() { 
    Square::draw(); 
    ShapeWithTextBox::draw(); 
} 

這是沒有必要從Shape獲得ShapeWithTextBox。它取決於Shape class的接口。

+0

謝謝,這是一個有趣的答案,但是當我從doubleclick事件中得到一個指針時,它將是一個Shape *。我如何使用它來訪問ShapeWithTextBox的成員?我不能施放它,因爲根據它的形狀,第二個基類的地址將被不同的數量抵消。 – iwbnwif

+0

另外我只注意到你的MySquare類可能遭受'鑽石'多重繼承問題,因爲Shape是Square和ShapeWithTextBox的超類 – iwbnwif

+0

鑽石問題 - 歡迎來到多繼承解決方案:) – dmitri