QGraphicsScene casting to derived class failed
-
My code is implementing subclasses of QGraphicsScene and QGraphicsItem in order to define some additional members.
In my MainWindow , a QGraphicsPG object (subclass of QGraphicsItem) is constructed and added to the GraphicsScenePG object (subclass of QGraphicsScene).
Then, a QGraphicsPG function compute() is called and need to access some members of GraphicsScenePG , but I was not able to cast the scene() pointer of type QGraphicsScene to the subclass pointer of type QGraphicsPG .
I tried:-
implicit or explicit cast: compilation error
-
static_cast and dynamic cast: both compile OK but fail during execution
-
reinterpret_cast: I did not try this quite dangerous operator...
Here below my (simplified) code with the dynamic_cast attempt:
// class GraphicsScenePG (header) #include <QGraphicsScene> class GraphicsScenePG : public QGraphicsScene { public: int nbMax ; GraphicsScenePG(); } // class GraphicsScenePG (implementation) #include "GraphicsScenePG.h" GraphicsScenePG::GraphicsScenePG() : QGraphicsScene() { nbMax= 1 ; } // class QGraphicsPG (header) #include <QGraphicsItem> class PG_Qt_MainWindow ; class QGraphicsPG : public QGraphicsItem { public: QGraphicsPG( QGraphicsItem *parent = 0 ); ~QGraphicsPG(); QRectF boundingRect() const ; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ; void compute() ; } // class QGraphicsPG (implementation) #include <QtGui> #include "qgraphicspg.h" #include "pg_qt_mainwindow.h" QGraphicsPG::QGraphicsPG(QGraphicsItem *parent) : QGraphicsItem(parent) { //... } void QGraphicsPG::compute() { GraphicsScenePG *scene= (dynamic_cast<GraphicsScenePG*>(this->scene()) ) ; // cast failed! qDebug()<<"casted pointer="<<scene ; } // class PG_Qt_MainWindow (header) #include <QMainWindow> #include "GraphicsScenePG.h" namespace Ui { class PG_Qt_MainWindow; } class PG_Qt_MainWindow : public QMainWindow { Q_OBJECT public: explicit PG_Qt_MainWindow(QWidget *parent = 0); ~PG_Qt_MainWindow(); private slots: void PG_Qt_MainWindow::on_actionDummy_triggered(); private: Ui::PG_Qt_MainWindow *ui; GraphicsScenePG scene ; }; // class PG_Qt_MainWindow (implementation) #include "pg_qt_mainwindow.h" #include "ui_pg_qt_mainwindow.h" #include <QtGui> PG_Qt_MainWindow::PG_Qt_MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::PG_Qt_MainWindow) , scene() { ui->setupUi(this); ui->graphicsView->setScene(&scene); ui->graphicsView->show() ; qDebug()<<"nbMax="<<scene.nbMax ; // OK so far! } void PG_Qt_MainWindow::on_actionDummy_triggered(); { QGraphicsPG* item= new QGraphicsPG(0) ; scene.addItem(item); item.compute() ; }
Execution gives:
casted pointer= QObject(0x0)
Trying to access the nbMax member from this incorrect pointer (null pointer?) crashes the execution.
Of course, I could circumvent the issue e.g. passing the scene pointer of type GraphicsScenePG directly as an argument to the constructor of QGraphicsPG but that's no clean coding, in my view...
Is there anything special about some Qt objects that prevents downcasting ? -
-
Hi
Did you try
http://doc.qt.io/qt-5/qobject.html#qobject_cast -
Hi
Did you try
http://doc.qt.io/qt-5/qobject.html#qobject_cast@mrjj
Thanks for your suggestion!
I added the Q_OBJECT macro in the GraphicsScenePG header and tried the cast:GraphicsScenePG *scene= qobject_cast<GraphicsScenePG*>(this->scene()) ;
But obtained the same result as with dynamic_cast or static_cast (compiles but cast fails; access to nbMax crashes the execution).
By the way, I figured out that the Q_OBJECT macro might be missing also in the QGraphicsPG header, so I added it there, but then the code won't compile anymore, saying:D:\Qt-apps\PG_Qt\qgraphicspg.cpp:-1: erreur : undefined reference to `vtable for QGraphicsPG'
Waou
-
@TGVF said in QGraphicsScene casting to derived class failed:
QGraphicsItem
As far as i recall. QGraphicsItem is not a QObject subclass?
Its very odd with the cast. i see no reason it should not work.
this->scene() does return something non NULL? -
My code is implementing subclasses of QGraphicsScene and QGraphicsItem in order to define some additional members.
In my MainWindow , a QGraphicsPG object (subclass of QGraphicsItem) is constructed and added to the GraphicsScenePG object (subclass of QGraphicsScene).
Then, a QGraphicsPG function compute() is called and need to access some members of GraphicsScenePG , but I was not able to cast the scene() pointer of type QGraphicsScene to the subclass pointer of type QGraphicsPG .
I tried:-
implicit or explicit cast: compilation error
-
static_cast and dynamic cast: both compile OK but fail during execution
-
reinterpret_cast: I did not try this quite dangerous operator...
Here below my (simplified) code with the dynamic_cast attempt:
// class GraphicsScenePG (header) #include <QGraphicsScene> class GraphicsScenePG : public QGraphicsScene { public: int nbMax ; GraphicsScenePG(); } // class GraphicsScenePG (implementation) #include "GraphicsScenePG.h" GraphicsScenePG::GraphicsScenePG() : QGraphicsScene() { nbMax= 1 ; } // class QGraphicsPG (header) #include <QGraphicsItem> class PG_Qt_MainWindow ; class QGraphicsPG : public QGraphicsItem { public: QGraphicsPG( QGraphicsItem *parent = 0 ); ~QGraphicsPG(); QRectF boundingRect() const ; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) ; void compute() ; } // class QGraphicsPG (implementation) #include <QtGui> #include "qgraphicspg.h" #include "pg_qt_mainwindow.h" QGraphicsPG::QGraphicsPG(QGraphicsItem *parent) : QGraphicsItem(parent) { //... } void QGraphicsPG::compute() { GraphicsScenePG *scene= (dynamic_cast<GraphicsScenePG*>(this->scene()) ) ; // cast failed! qDebug()<<"casted pointer="<<scene ; } // class PG_Qt_MainWindow (header) #include <QMainWindow> #include "GraphicsScenePG.h" namespace Ui { class PG_Qt_MainWindow; } class PG_Qt_MainWindow : public QMainWindow { Q_OBJECT public: explicit PG_Qt_MainWindow(QWidget *parent = 0); ~PG_Qt_MainWindow(); private slots: void PG_Qt_MainWindow::on_actionDummy_triggered(); private: Ui::PG_Qt_MainWindow *ui; GraphicsScenePG scene ; }; // class PG_Qt_MainWindow (implementation) #include "pg_qt_mainwindow.h" #include "ui_pg_qt_mainwindow.h" #include <QtGui> PG_Qt_MainWindow::PG_Qt_MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::PG_Qt_MainWindow) , scene() { ui->setupUi(this); ui->graphicsView->setScene(&scene); ui->graphicsView->show() ; qDebug()<<"nbMax="<<scene.nbMax ; // OK so far! } void PG_Qt_MainWindow::on_actionDummy_triggered(); { QGraphicsPG* item= new QGraphicsPG(0) ; scene.addItem(item); item.compute() ; }
Execution gives:
casted pointer= QObject(0x0)
Trying to access the nbMax member from this incorrect pointer (null pointer?) crashes the execution.
Of course, I could circumvent the issue e.g. passing the scene pointer of type GraphicsScenePG directly as an argument to the constructor of QGraphicsPG but that's no clean coding, in my view...
Is there anything special about some Qt objects that prevents downcasting ?@TGVF said in QGraphicsScene casting to derived class failed:
void PG_Qt_MainWindow::on_actionDummy_triggered(); { QGraphicsPG* item= new QGraphicsPG(0) ; scene.addItem(item); item.compute() ; }
I might be rushing in, because I'm not a C++-er, but
item
is a pointer to aQGraphicsPG
, and yet you callitem.compute()
notitem->compute()
? How does that work? (It doesn't perchance do it like callingnullptr->compute()
, where C++ allows you to call member functions on a null instance, giving them a nullthis
, does it?) Incompute()
you should deffo print outthis->scene()
before you do your cast. EDIT: Also, ifthis-scene()
is non-null, trydynamic_cast<QGraphicsScene*>(this->scene())
?Or is all this code not the literal code used before you "simplified"?
-
-
@TGVF said in QGraphicsScene casting to derived class failed:
void PG_Qt_MainWindow::on_actionDummy_triggered(); { QGraphicsPG* item= new QGraphicsPG(0) ; scene.addItem(item); item.compute() ; }
I might be rushing in, because I'm not a C++-er, but
item
is a pointer to aQGraphicsPG
, and yet you callitem.compute()
notitem->compute()
? How does that work? (It doesn't perchance do it like callingnullptr->compute()
, where C++ allows you to call member functions on a null instance, giving them a nullthis
, does it?) Incompute()
you should deffo print outthis->scene()
before you do your cast. EDIT: Also, ifthis-scene()
is non-null, trydynamic_cast<QGraphicsScene*>(this->scene())
?Or is all this code not the literal code used before you "simplified"?
@JonB
In fact, this "simplified" code is not the literal one; actually , the operator -> is used, not "." . Otherwise, it would not compile.
I now debug-print as follows:qDebug()<<"original scene pointer="<<(int)(this->scene()) ; qDebug()<<"dynamic_casted scene pointer="<<(int)(dynamic_cast<GraphicsScenePG*>(this->scene()) ) ; qDebug()<<"qobject_casted scene pointer="<<(int)(qobject_cast<GraphicsScenePG*>(this->scene()) ) ; qDebug()<<"original scene width()="<<(this->scene()->width()) ;
which dumps the following lines:
original scene pointer= 0 dynamic_casted scene pointer= 0 qobject_casted scene pointer= 0
And then run crashes (of course!) since the scene()->width() can't be accessed.
So the problem is not with the cast statement but with the scene() function returning NULL.
Nonethless, this QGraphicsItem does paint correctly on the scene as it is visible in the window.
May be because it was constructed with (default) parent=0 ? Documentation says constructing with parent=0 is possible if addItem(item) is used. Is this the reason why scene() returns NULL? -
@JonB
In fact, this "simplified" code is not the literal one; actually , the operator -> is used, not "." . Otherwise, it would not compile.
I now debug-print as follows:qDebug()<<"original scene pointer="<<(int)(this->scene()) ; qDebug()<<"dynamic_casted scene pointer="<<(int)(dynamic_cast<GraphicsScenePG*>(this->scene()) ) ; qDebug()<<"qobject_casted scene pointer="<<(int)(qobject_cast<GraphicsScenePG*>(this->scene()) ) ; qDebug()<<"original scene width()="<<(this->scene()->width()) ;
which dumps the following lines:
original scene pointer= 0 dynamic_casted scene pointer= 0 qobject_casted scene pointer= 0
And then run crashes (of course!) since the scene()->width() can't be accessed.
So the problem is not with the cast statement but with the scene() function returning NULL.
Nonethless, this QGraphicsItem does paint correctly on the scene as it is visible in the window.
May be because it was constructed with (default) parent=0 ? Documentation says constructing with parent=0 is possible if addItem(item) is used. Is this the reason why scene() returns NULL?May be because it was constructed with (default) parent=0 ? Documentation says constructing with parent=0 is possible if addItem(item) is used. Is this the reason why scene() returns NULL?
I don't think that will matter because your
scene.addItem(item);
will set its parent. But if you want to be sure, why don't you just passscene
to the constructor to test, and then you'll know?It can be difficult to tell when the code shown is not the actual code compiled...
-
May be because it was constructed with (default) parent=0 ? Documentation says constructing with parent=0 is possible if addItem(item) is used. Is this the reason why scene() returns NULL?
I don't think that will matter because your
scene.addItem(item);
will set its parent. But if you want to be sure, why don't you just passscene
to the constructor to test, and then you'll know?It can be difficult to tell when the code shown is not the actual code compiled...
@JonB
Oups, I found my blunder! In the body of QGraphicsPG constructor (not shown on my simplified code), the compute() function is also called i.e. BEFORE this object is added to the scene, hence scene() is not yet allocated a value.
In the subsequent calls made by the slot on_actionDummy_triggered, everything is OK and dynamic_cast works perfectly.
Thanks JonB a lot for your help!