Multiple inheritance (diamond) problem



  • Hi,
    I am stuck with a diamond inheritance problem, and was wondering what would be the proper way to fix it.
    I am using the QGraphicsView framework, but as I would like to change a lot of behavioural details I tried to subclass some of the Qt classes that I use. However, these are also subclasses of each other, and the compiler starts to complain about ambiguous bases.

    In this case, I subclass these two classes:
    QGraphicsItem -> MyItem
    QGraphicsTextItem -> MyTextItem
    I would like MyTextItem to also enjoy the modifications that I made in MyItem, so I tried:
    @
    class MyTextItem : public MyItem, public QGraphicsTextItem
    @

    This fails with the error "'QGraphicsItem' is an ambiguous base of 'MyTextItem'". This because QGraphicsItem is inherited by both QGraphicsTextItem and by MyItem.

    Possible solutions that I see:
    1: Use virtual inheritance [1]. This seems ideal to me, exept that it requires a change to the QGraphicsTextItem because it should declare QGraphicsItem as a virtual base. Changing stuff in Qt is outside the scope of my project, and I would not know if changing this would have any side effects. Is there a reason for Qt to not have this inheritance be virtual?
    2: Implementing the methods from MyItem again in MyTextItem, instead of inheriting them. Seems a silly solution.
    3: Not having MyItem derive from QGraphicsItem, but then it cannot do anything with the protected part of QGraphicsItem, and it looks like an ugly way around.
    4: Forget about inheritance and use some other way to modify the standard behaviour, like using the 'charm pattern' [2]. Not sure how that would work, and I wonder if the code would become legible (and I thought this is what inheritance was made for).

    I hope there is some simple and clear way to do this that I just did not think about. Can anyone tell how this kind of problem is usually solved?

    Gerben

    [1] An explanation of virtual inheritance and the diamond problem: http://www.cprogramming.com/tutorial/virtual_inheritance.html
    [2] A proposed solution in a related thread: http://qt-project.org/forums/viewreply/66091/



  • In a similar situation, I used templates.

    I created a template class, where the template argument was the class to inherit from. Then, I inherited again from this template. This way, I was able to share my common modifications to the classes without ending up in a diamond pattern.

    So, something like this:
    @
    template <class T> //let T be a QGraphicsItem or a class derived from it (or a class that supports the same interface)
    class GraphicsItemExtensions: public T
    {
    //... your extensions to QGraphicsItem
    }

    class MyItem: public GraphicsItemExtension<QGraphicsItem>
    {
    //... your MyItem specific stuff
    }

    class MyTextItem: public GraphicsItemExtension<QGraphicsTextItem>
    {
    // ... your MyTextItem specific stuff
    }
    @

    Works well. The only limitation is that you can't add signals and slots (or use other moc-dependend stuff) in the GraphicsItemExtension template class, as moc doesn't support templates. However, you can in the concrete implemenations again.

    Charms are sometimes a solution as well. I have never tried this approach with QGraphicsItem. It does seem that you can manipulate the items from the outside though, perhaps by inserting the 'charm' as the parent of the item and abusing the filtering that parent items can do on events targetted at the child.



  • Hi,
    I can't understand your need to MyItem if it's a simple QGraphicsItem !
    Try to find a way to construct your class MyTextItem like this :
    @
    class MyTextItem : public QGraphicsTextItem
    @
    according to "this tutorial ":http://en.wikipedia.org/wiki/Virtual_inheritance the problem is what type to cast to.
    If this is the problem you can use the graphics Items casting :
    @
    T qgraphicsitem_cast ( QGraphicsItem * item )
    @
    But before you have to reimplement the virtual type() method like this :
    @
    int QGraphicsItem::type () const
    {
    return Type;
    }
    @
    And add this line to your class :
    @
    public:
    enum { Type = UserType + your_type }; // your_type > 0
    @

    The Type value is used by qgraphicsitem_cast() to distinguish between the custom items in order to decide what type to cast the item to !

    good luck :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.