views:

89

answers:

4

I have a series of classes representing "smart" map elements: MapTextElement, MapIconElement, etc. The classes are extending various Qt graphics item classes, but also provide common functionality, such as an abstract factory method that returns a property panel specialized for each class. I have declared these common methods in a pure virtual class, MapElementInterface. My classes then multiply-inherit the appropriate Qt base class as well as the interface:

class MapTextElement : public QGraphicsTextItem, public MapElementInterface
class MapIconElement : public QGraphicsItem, public MapElementInterface

So my class hierarchy looks kind of like:

         +-------------+    +-------------------+
         |QGraphicsItem|    |MapElementInterface|
         +-------------+    +-------------------+
                ^                   ^   ^
                |                   |   |
         +------+------+            |   |    
         |             |            |   |
+-----------------+   +--------------+  |
|QGraphicsTextItem|   |MapIconElement|  |
+-----------------+   +--------------+  |
     ^                                  |
     |                                  |
     +-------------------+        +-----+
                         |        |
                      +--------------+
                      |MapTextElement|
                      +--------------+

I am receiving a pointer to a QGraphicsItem from a Qt-provided method. In this case, I know that the pointer is not only QGraphicsItem, but also MapElementInterface. I want to treat the pointer as a MapElementInterface.

QList<QGraphicsItem*> selected = scene_->selectedItems();
if (selected.count() == 1) {
  // We know that the selected item implements MapEditorInterface
  MapElementInterface *element = SOME_CAST_HERE<MapElementInterface*>(selected[0]);
  QWidget *panel = element->GeneratePropertyPanel(property_dock_);
}

What is the proper cast to use? Or am I going about this completely the wrong way?

+2  A: 

You have to be careful here, because given the diagram your pointer could point to either MapTextElement or MapIconElement. The only safe bet for you here is to go with dynamic casting. Or provide another way for yourself to figure the object's type.

Vlad
+1  A: 

You can cast to MapIconElement, and then to MapElementInterface, or you can cast to MapTextElement, then to MapElementInterface. You must chose a path (or dynamic-down cast to check what path you take).

Alexandre C.
Can you clarify? Are you saying that there no way to directly cast to MapElementInterface? If that is the case, then every time I add a new concrete class of MapElementInterface, I have to add another `if` path to my code. That smells, and largely defeats the purpose of the interface.
Dave
Exactly. I'm afraid you have to dynamic_cast downwards (indeed not cool), or turn MapElementInterface into a derived class of QGraphicsItem. Or maybe turn MapElementInterface inheritance into some member of ...Element.
Alexandre C.
`dynamic_cast` seems to be working for me, so I must not be running into the problem you are describing. Thanks anyway for the help!
Dave
+2  A: 

With multiple inheritance, dynamic_cast is the only way, and check the return value against NULL.

Frederik Slijkerman