When using the Graphics View Framework, it is necessary to cast the QGraphicSitem object. My experience is particularly classic scene is in QGraphicsView: : mousePressEvent used in QGraphicsView: : itemAt gets the current selected item. And then you type it and then you do something about it.

QGraphicSitem is just a base class, and if we want to get the real subclass type at Runtime, we have to cast it. There are many options for functions related to Type casting, including the C++ static_cast, dynamic_cast and Qt’s qobject_cast. Let’s start with dynamic_cast, which looks perfect and returns nullptr if it fails. But we should try to avoid using RTTI.

Then there’s the static_cast, which is essentially a function that casts by overwriting a fixed length of memory. Therefore, it is not possible to judge whether a conversion of a type was successful by this strong conversion.

Let’s do some small experiments with dynamic_cast and static_cast. As you can see from Experiment 1, if the statement is commented out, the program crashes. The reason is that C is Nullptr. Let’s also look at Experiment 2, which results in the output “B” and calls class B:: Hello, an unexpected result.

class A { public: virtual void hello() { qDebug() << a; }; private: const char* a {"a"}; }; class B : public A { public: void hello() override { qDebug() << b; } private: const char* b {"b"}; }; class C : public A { public: void hello() override { qDebug() << c; } private: const char* c {"c"}; }; Int main() {A* b = new b; auto c = dynamic_cast<C*>(b); // if (c ! = nullptr) c->hello(); // crash!!! } // int main() {A* b = new b; auto c = static_cast<C*>(b); c->hello(); // output b}

And finally, qobject_cast, which is kind of Qt’s own son. But it doesn’t work with QGraphicSitem, which ultimately doesn’t inherit QObject. If you want to use QOBJECT_CAST, you can choose QGraphicsObject as the base class.

In addition to the three type casting functions described above, Qt provides QGraphicSitem’s own family of type conversion functions, QGraphicSitem_Cast. Its advantage is that it does not use RTTI and returns NullPtr if the conversion fails.

As you can see from the source code, its implementation is quite simple. The result of the transformation is determined by whether Item::Type is equal or not.

template <class T> inline T qgraphicsitem_cast(QGraphicsItem *item)
{
    typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type Item;
    return int(Item::Type) == int(QGraphicsItem::Type)
        || (item && int(Item::Type) == item->type()) ? static_cast<T>(item) : 0;
}
template <class T> inline T qgraphicsitem_cast(const QGraphicsItem *item)
{
    typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type Item;
    return int(Item::Type) == int(QGraphicsItem::Type)
        || (item && int(Item::Type) == item->type()) ? static_cast<T>(item) : 0;
}

In fact, this qgraphicsitem_cast also has its drawbacks. Since it is a simple comparison of QGraphicSitem ::Type to determine whether the conversion was successful, it is limited to determining whether two subclasses inherit from the same base class.

class A : public QGraphicsItem { // ... }; class B: public QGraphicsItem { // ... }; int main() { auto a = new A; auto b = new B; qDebug() << a->type() == b->type(); // True auto c = qGraphicSitem_cast <A*>(b); If (c!); if (c!); = nullptr) qDebug() << "true"; }

If you want the exact type, use dynamic_cast. If you just need to determine whether you inherit from the same base class, you can use QGraphicSitem_Cast.