I am facing a problem in my app where i want the qgraphicsitem_cast to cast items properly anywhere along hierarchy. I can't use dynamic_cast since i am compiling without rtti support.
Example:
if Base inherits QGraphicsItem and Derived inherits Base and both the classes define(or declare) Type as well type() which point to different values, then the cast fails even though its legal as shown below.
Derived *d = new Derived();
Q_ASSERT (qgraphicsitem_cast<Derived*>(item)); Succeeds
Q_ASSERT (qgraphicsitem_cast<Base*>(item)); //This fails though legal :(
Derived *d = new Derived();
QGraphicsItem *item = d;
Q_ASSERT (qgraphicsitem_cast<Derived*>(item)); Succeeds
Q_ASSERT (qgraphicsitem_cast<Base*>(item)); //This fails though legal :(
To copy to clipboard, switch view to plain text mode
My current solution is custom cast function as shown
//stolen from source of qgraphicsitem_cast but modified to suit my needs
template <class T>
inline T graphicsitem_cast
(QGraphicsItem *item
) {
bool firstCond
= int(static_cast<T>
(0)->Type
) == int(QGraphicsItem::Type);
bool secondCond = !firstCond && item && ((int(static_cast<T>(0)->Type) & item->type()) == (int(static_cast<T>(0)->Type)));
bool result = firstCond | secondCond;
return result ? static_cast<T>(item) : 0;
}
//stolen from source of qgraphicsitem_cast but modified to suit my needs
template <class T> inline T graphicsitem_cast(QGraphicsItem *item)
{
bool firstCond = int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type);
bool secondCond = !firstCond && item && ((int(static_cast<T>(0)->Type) & item->type()) == (int(static_cast<T>(0)->Type)));
bool result = firstCond | secondCond;
return result ? static_cast<T>(item) : 0;
}
To copy to clipboard, switch view to plain text mode
Notice the bitwise AND used in secondCond. qgraphicsitem_cast on other hand uses "==" and hence it fails.
Now I define my hierarcy as follows(with woking eg)
#include <QtGui>
//stolen from source of qgraphicsitem_cast but modified to suit my needs
template <class T>
inline T graphicsitem_cast
(QGraphicsItem *item
) {
bool firstCond
= int(static_cast<T>
(0)->Type
) == int(QGraphicsItem::Type);
bool secondCond = !firstCond && item && ((int(static_cast<T>(0)->Type) & item->type()) == (int(static_cast<T>(0)->Type)));
bool result = firstCond | secondCond;
return result ? static_cast<T>(item) : 0;
}
const int startValue = 65536;
{
public:
enum { Type = startValue };
int type() const { return Type;}
};
class Derived1 : public Base
{
public:
enum { Type = (startValue << 1) | Base::Type };
Derived1() : Base() {}
int type() const { return Type;}
};
class Derived2 : public Derived1
{
public:
enum { Type = (startValue << 2) | Derived1::Type };
Derived2() : Derived1() {}
int type() const { return Type;}
};
int main()
{
Base *base = new Base();
Derived1 *d1 = new Derived1();
Derived2 *d2 = new Derived2();
if(graphicsitem_cast<Base*>(item) != 0) {
//Check for crash
qDebug() << item->flags();
}
if(graphicsitem_cast<Derived1*>(item) != 0) {
//Check for crash
qDebug() << item->flags();
}
if(graphicsitem_cast<Derived2*>(item) != 0) {
//Check for crash
qDebug() << item->flags();
}
//All above succeeds
return 0;
}
#include <QtGui>
//stolen from source of qgraphicsitem_cast but modified to suit my needs
template <class T> inline T graphicsitem_cast(QGraphicsItem *item)
{
bool firstCond = int(static_cast<T>(0)->Type) == int(QGraphicsItem::Type);
bool secondCond = !firstCond && item && ((int(static_cast<T>(0)->Type) & item->type()) == (int(static_cast<T>(0)->Type)));
bool result = firstCond | secondCond;
return result ? static_cast<T>(item) : 0;
}
const int startValue = 65536;
class Base : public QGraphicsLineItem
{
public:
enum { Type = startValue };
Base() : QGraphicsLineItem() {}
int type() const { return Type;}
};
class Derived1 : public Base
{
public:
enum { Type = (startValue << 1) | Base::Type };
Derived1() : Base() {}
int type() const { return Type;}
};
class Derived2 : public Derived1
{
public:
enum { Type = (startValue << 2) | Derived1::Type };
Derived2() : Derived1() {}
int type() const { return Type;}
};
int main()
{
Base *base = new Base();
Derived1 *d1 = new Derived1();
Derived2 *d2 = new Derived2();
QGraphicsItem *item = d2;
if(graphicsitem_cast<Base*>(item) != 0) {
//Check for crash
item->setFlags( QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsSelectable );
qDebug() << item->flags();
}
if(graphicsitem_cast<Derived1*>(item) != 0) {
//Check for crash
item->setFlags( QGraphicsItem::ItemIsFocusable );
qDebug() << item->flags();
}
if(graphicsitem_cast<Derived2*>(item) != 0) {
//Check for crash
item->setFlags( QGraphicsItem::ItemIsSelectable );
qDebug() << item->flags();
}
//All above succeeds
return 0;
}
To copy to clipboard, switch view to plain text mode
The problem is I don't think this is elegant
Is there any elegant solution ? Can I use any template tricks in a better way ?
Bookmarks