2013-10-17 164 views
2

我正在SFML中實現可視化樹。 SFML包含兩個重要的圖紙類別:sf::Drawablesf::Transformable。如果將它們捆綁在一起,那就太好了,但它們不是。許多對象來自繼承,即:僅通過繼承自其他類來定義類型

class SFML_GRAPHICS_API Text : public Drawable, public Transformable 

class SFML_GRAPHICS_API Sprite : public Drawable, public Transformable 

class SFML_GRAPHICS_API Shape : public Drawable, public Transformable 

對於我的視覺樹,我有一個SceneNode類,從繪製對象和變形的繼承和繪製函數將調用私有的onDraw本身,然後它的孩子。但是,許多SFML本機類(如sf::Text)具有私有的繪圖函數。所以,我無法創建類似

class Text: public sf::Text, public SceneNode 

然後把它放到可視化樹中。對於這些本地類,我不需要它們繪製孩子,我只是希望能夠將它們添加到視覺樹中作爲葉節點。問題的關鍵是視覺樹的每個成員需要繼承sf::Drawablesf::Tranformable。我需要能夠定義從這兩個繼承的類型。如果我定義虛擬類別

class LeafNode: public sf::Drawable, public sf::Tranformable { } 

它似乎定義了我想要的類型。然後,SceneNode將包含std::vector<LeafNode*> m_children。繪製這些孩子時,我會對每個物品進行動態投射,看它是否爲SceneNode,然後調用繪畫函數,以便SceneNode繪製其子元素。

然而,下面的代碼不會編譯由於類型不兼容:

LeafNode * node = new sf::Text("PLAY", font, 20); 

理想情況下,我想定義類似

std::vector<sf::Drawable, sf::Transformable*> m_children 

如果是編造的語法意味着每個元素必須派生來自sf::Drawablesf::Transformable。這可能嗎?

回答

0

然而,許多本土SFML類,如SF ::文本,有平局的功能是私人

這並不完全正確。由於sf::Drawable::draw功能被保護,因此方法sf::Text也被保護。這是C++的複雜規則之一。

所以,我不能創建一個類像

class Text: public sf::Text, public SceneNode 

如果你做了,你會在你的層次中兩個sf::Drawablesf::Transformable基類,一個從sf::Text和一個從SceneNode。那不會很好。

繪製這些孩子時,我會對每個項目做一個動態轉換,看它是否是一個SceneNode,然後調用一個繪圖函數,以便SceneNode繪製其子元素。

我不會推薦這樣的設計。使用dynamic_cast通常是您的軟件設計不太好的標誌。 (我不想在這個話題上談論太多,谷歌關於這個話題。)

但是,讓我們回答您的基本問題:

如果是編造的語法意味着每個元素必須來自SF ::繪製對象和SF ::變形的派生。這可能嗎?

不,不管怎樣,你可以做更簡單的事情。

而不是從sf::TextSceneNode繼承Text,定義您的類爲包裝。它可以如此簡單:

class Text : public SceneNode { 
    sf::Text m_text; 
public: 
    sf::Text& get() { return m_text; } 

    // Override SceneNode drawing method: 
    virtual void onDraw(RenderTarget& target) const 
     // Draw m_text: 
     target.draw(m_text); 
    } 
}; 

雖然這個快速包裝有兩個缺陷。 a)它不使用SceneNode的可轉換部分。 b)由於封裝被破壞了get(),所以用戶可以修改兩個可變形:SceneNodesf::Text之一。

對於a),修正b應該是直截了當的。爲了修復b),你必須使包裝更復雜一點:不是有這個醜陋的get(),而是編寫方法來設置底層sf::Text的屬性,這些屬性並沒有鏈接到sf::Transformable,例如, setColor

0

不知道任何關於SMFL(這可能會提供更好的解決方案)我認爲你可以實現這個向量。你只需要定義自己的指針包裝,只接受指針從多個類型繼承對象:

template <class T1, class T2> 
struct special_pointer_wrapper 
{ 
    T1* t1; 
    T2* t2; 
    template<class T> 
    special_pointer_wrapper(T* p) 
     : t1(dynamic_cast<T1*>(p)) 
     , t2(dynamic_cast<T2*>(p)) 
    { 
     if ((p1==0) || (p2==0)) 
      throw "Error"; 
    } 

    getT1 T1*() const { return t1; } 
    getT2 T2*() const { return t2; } 
}; 

這個類接收任何指針,並確保其指向的類型是從T1和T2導出(甚至如果它們看起來完全不相關)。如果它不是派生的對象,它會拋出。通過函數getT1()getT2(),您可以訪問指向兩個基類的指針。

請注意,施工可能會很慢,因爲dynamic_cast但提取的類型是O(1)。