仅通过从其他类继承来定义类型

时间:2013-10-17 17:13:41

标签: c++ inheritance sfml

我在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

对于我的可视化树,我有一个继承自Drawable和Transformable的SceneNode类,而draw函数将调用私有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派生。这可能吗?

2 个答案:

答案 0 :(得分:0)

  

但是,许多SFML本机类(如sf :: Text)都具有私有的绘制功能

这不是真的。由于sf::Drawable::draw函数受到保护,因此draw sf::Text方法也受到保护。这是C ++的复杂规则之一。

  

所以,我不能创建像

这样的类
class Text: public sf::Text, public SceneNode

如果您这样做,您的层次结构中将有两个sf::Drawablesf::Transformable个基类,一个来自sf::Text,另一个来自SceneNode。那不太好。

  

绘制这些子项时,我会对每个项目进行动态转换以查看它是否为SceneNode,然后调用绘制函数,以便SceneNode绘制其子项。

我不推荐这样的设计。使用dynamic_cast通常表明您的软件设计并不是那么好。 (我不想过多讨论这个话题,谷歌关于那个话题。)

但让我们回答你的基本问题:

  

其中包含的语法意味着每个元素必须从sf :: Drawable和sf :: Transformable派生。这可能吗?

没有。但无论如何,你可以做更简单的事情。

不要让Text继承sf::TextSceneNode,而是将您的类定义为包装器。它可以很简单:

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),你必须使包装器更复杂一点:编写方法来设置未链接到{{1的基础get()的属性,而不是使用这个丑陋的sf::Text。例如sf::Transformable

答案 1 :(得分: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)。