2013-10-17 85 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)。