PDA

View Full Version : Cast from base class to derived, multiple inheritance



ivareske
17th August 2013, 16:44
Hi, I have a class defined like this:
class GraphicsPCRectItem : public QGraphicsRectItem, public GraphicsPCItem{...

QGraphicsRectItem inherits from QAbstractGraphicsShapeItem and QGraphicsItem, while GraphicsPCItem does not inherit from any class.

In a function in a subclass I have of QGraphicsView I want to access a GraphicsPCRectItem at a certain position in the view, so what I try is ('v' is a pointer to my QGraphicsView subclass, loc is the position relative to the QGraphuicsView subclass):

QGraphicsItem *baseItem = (v->itemAt(loc)); //ok
QGraphicsRectItem *rectItem = dynamic_cast<QGraphicsRectItem*>(baseItem); //ok
GraphicsPCRectItem *item = dynamic_cast<GraphicsPCRectItem*>(rectItem); //NULL

How can I cast correctly and access the item which is actually of type GraphicsPCRectItem?

amleto
17th August 2013, 19:29
Dynamic cast is correct. You're obviously not doing what you say you are.

this works for me:


#include <iostream>

class Base
{
public:
virtual void foo(){}
};

class Mixin
{
};

class Middle : public Base, public Mixin
{
};


class Der : public Middle
{
};

using std::cout;
using std::cin;

int main()
{
Base* base = new Der();

Middle* middle = dynamic_cast<Middle*>(base);

Der* der1 = dynamic_cast<Der*>(base);
Der* der2 = dynamic_cast<Der*>(middle);
Der* der3 = static_cast<Der*>(base);

cout << der1 << '\n';
cout << der2 << '\n';
cout << der3 << '\n';

cin.get();
}


By the way, 'up casting' is sometimes a sign of missing/poor design.

ivareske
17th August 2013, 22:15
Hmm, thank you, better check my code again then... I know it is the correct QGraphicsItem I try to cast, I tested by giving the GraphicsPCRectItem a tooltip in its constructor, and printing the tooltip of the 'baseItem'. Does the order I inherit have anything to say, or anything regarding virtual stuff?

d_stranz
17th August 2013, 23:20
Does the order I inherit have anything to say, or anything regarding virtual stuff?

No. However, if your compiler has an RTTI (run-time type information) flag, make sure it is set to true (or "on"). dynamic_cast<> depends on it. In most modern compilers, I think it is now on by default.

I think your problem is that the instance you are trying to cast really isn't what you think it is, otherwise amleto's example would work for your code.

----Edit ----

Ah, no never mind. It is your code that is wrong.



QGraphicsItem *baseItem = (v->itemAt(loc)); //ok
QGraphicsRectItem *rectItem = dynamic_cast<QGraphicsRectItem*>(baseItem); //ok
GraphicsPCRectItem *item = dynamic_cast<GraphicsPCRectItem*>(rectItem); //NULL


The problem is the last line: "rectItem" is not a pointer to a GraphicsPCRectItem, it is a pointer to a QGraphicsRectItem. QGraphicsRectItem does not inherit from anything that can be cast to a GraphicsPCRectItem, so the dynamic_cast<> is doing exactly what it is supposed to, telling you that, "No, can't cast this to that".

Remove the second line, and change "rectItem" to "baseItem" in the dynamic cast to GraphicsPCRectItem, and everything will be fine.

amleto
18th August 2013, 02:49
d_stranz, re: your edit: isn't that exactly my example where first middle is cast from base, and then der2 is cast from middle? What you have written seems to suggest that dynamic_cast cannot up-cast, which it can.

and to be precise with the language, from the op's code we don't know what the pointer is pointing to so we cannot say what type the instance is.

ivareske
18th August 2013, 13:02
Thank you all, it works now by casting directly from the baseItem to GraphicsPCRectItem. In addition, there was a problem with only the top item at a certain position being returned, which sometimes was not the correct item. So what I do now is:

QList<QGraphicsItem*> baseItems = v->items(loc);
for(int i=0;i<baseItems.size();i++){
QGraphicsItem *baseItem = baseItems[i];

if(!baseItem){
continue;
}

GraphicsPCRectItem *item = dynamic_cast<GraphicsPCRectItem*>(baseItem);
..............

amleto
18th August 2013, 15:19
Thank you all, it works now by casting directly from the baseItem to GraphicsPCRectItem. In addition, there was a problem with only the top item at a certain position being returned, which sometimes was not the correct item. So what I do now is:

QList<QGraphicsItem*> baseItems = v->items(loc);
for(int i=0;i<baseItems.size();i++){
QGraphicsItem *baseItem = baseItems[i];

if(!baseItem){
continue;
}

GraphicsPCRectItem *item = dynamic_cast<GraphicsPCRectItem*>(baseItem);
..............

bolded is the main problem here, nothing to do with casting issues. The cast returned null because the object isn't one of your PC classes.

NB Please use code tags - your code is unreadable. Also baseItem will never be null so having this block...


if(!baseItem){
continue;
}


...is pointless.

d_stranz
18th August 2013, 23:34
Something very strange here - except for amleto's last reply, none of the CODE-tagged items are appearing when I look at this thread. Anyone else have the same problem? (I'm looking at this in Firefox on a new Windows PC - I'll have to boot up my old PC and see if the same thing happens).

Not only that, but starting a couple of replies back, the thread title was hacked - "Buy Generic Cleocin Medicine Terbon". Looks to me like there's a security problem on Qt Centre or ivareske's machine.

amleto
19th August 2013, 00:39
I had to add extra newlines after the closing [ / code] to get it to show when I wrote it (yes, I have the same problem). The board was full of spam this morning so title change just a result of replying to spam message (now deleted).

I 'fixed' the reply title - 'hacking' not needed ;)