Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsTextItem * and void * conversion error
Forum Updated to NodeBB v4.3 + New Features

QGraphicsTextItem * and void * conversion error

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 6 Posters 691 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K ksz123

    I want to use void * to store the pointer of the QGraphicsTextItem object created, and in another function, convert the void * pointer to a QGraphicsItem pointer for easy removal from the scene. However, I found that during the conversion, item and item2 point to different addresses; When converting QGraphicsSimpleTextItem pointers, there is no such problem. May I ask why this is happening or where I am using the problem , here is my demo:

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        m_pScene=new QGraphicsScene(this);
        m_pView=new QGraphicsView(ui->viewWidget);
        m_pView->setScene(m_pScene);
    
        m_pView->setWindowTitle("Graphics View");
        m_pView->resize(500, 500);
    
        auto x=new QPixmap(R"(D:\desktop\Data\2D\2.bmp)");
        pV=new QGraphicsPixmapItem(*x);
        m_pScene->addItem(pV);
        //QGraphicsTextItem
        auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV);
        auto pItem=(void*)pTextItem;
    
        auto items=m_pScene->items();
        auto item=(QGraphicsTextItem*)pItem;
        auto b1=items.contains(item);
    
        auto item2=(QGraphicsItem*)pTextItem;
        auto b2=items.contains(item2);
    
        //QGraphicsSimpleTextItem
        auto pSimpleTextItem=new QGraphicsSimpleTextItem("QGraphicsSimpleTextItem",pV);
        auto pSimpleItem=(void*)pSimpleTextItem;
    
        auto SimpleItems=m_pScene->items();
        auto SimpleItem=(QGraphicsTextItem*)pSimpleItem;
        auto b3=SimpleItems.contains(SimpleItem);
    
        auto Simpleitem2=(QGraphicsItem*)pSimpleItem;
        auto b4=SimpleItems.contains(Simpleitem2);
    
        int i=0;
    }
    
    jsulmJ Offline
    jsulmJ Offline
    jsulm
    Lifetime Qt Champion
    wrote on last edited by
    #2

    @ksz123 said in QGraphicsTextItem * and void * conversion error:

    auto pItem=(void*)pTextItem;
    
    auto items=m_pScene->items();
    auto item=(QGraphicsTextItem*)pItem;
    auto b1=items.contains(item);
    
    auto item2=(QGraphicsItem*)pTextItem;
    

    Don't use C style casts!
    Use reinterpret_cast to cast to/from void*.
    Use dynamic_cat to cast in a class hierarchy.

    How did you validate that item and item2 contain different addresses?

    https://forum.qt.io/topic/113070/qt-code-of-conduct

    1 Reply Last reply
    0
    • K ksz123

      I want to use void * to store the pointer of the QGraphicsTextItem object created, and in another function, convert the void * pointer to a QGraphicsItem pointer for easy removal from the scene. However, I found that during the conversion, item and item2 point to different addresses; When converting QGraphicsSimpleTextItem pointers, there is no such problem. May I ask why this is happening or where I am using the problem , here is my demo:

      MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
          m_pScene=new QGraphicsScene(this);
          m_pView=new QGraphicsView(ui->viewWidget);
          m_pView->setScene(m_pScene);
      
          m_pView->setWindowTitle("Graphics View");
          m_pView->resize(500, 500);
      
          auto x=new QPixmap(R"(D:\desktop\Data\2D\2.bmp)");
          pV=new QGraphicsPixmapItem(*x);
          m_pScene->addItem(pV);
          //QGraphicsTextItem
          auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV);
          auto pItem=(void*)pTextItem;
      
          auto items=m_pScene->items();
          auto item=(QGraphicsTextItem*)pItem;
          auto b1=items.contains(item);
      
          auto item2=(QGraphicsItem*)pTextItem;
          auto b2=items.contains(item2);
      
          //QGraphicsSimpleTextItem
          auto pSimpleTextItem=new QGraphicsSimpleTextItem("QGraphicsSimpleTextItem",pV);
          auto pSimpleItem=(void*)pSimpleTextItem;
      
          auto SimpleItems=m_pScene->items();
          auto SimpleItem=(QGraphicsTextItem*)pSimpleItem;
          auto b3=SimpleItems.contains(SimpleItem);
      
          auto Simpleitem2=(QGraphicsItem*)pSimpleItem;
          auto b4=SimpleItems.contains(Simpleitem2);
      
          int i=0;
      }
      
      C Offline
      C Offline
      ChrisW67
      wrote on last edited by
      #3

      @ksz123 said in QGraphicsTextItem * and void * conversion error:

      I want to use void * to store the pointer of the QGraphicsTextItem object created, and in another function, convert the void * pointer to a QGraphicsItem pointer

      Why?

      1 Reply Last reply
      0
      • K Offline
        K Offline
        ksz123
        wrote on last edited by
        #4

        Sorry, it should be this demo
        MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
        {
        ui->setupUi(this);
        m_pScene=new QGraphicsScene(this);
        m_pView=new QGraphicsView(ui->viewWidget);
        m_pView->setScene(m_pScene);

        m_pView->setWindowTitle("Graphics View");
        m_pView->resize(500, 500);
        
        auto x=new QPixmap(R"(D:\desktop\Data\2D\2.bmp)");
        pV=new QGraphicsPixmapItem(*x);
        m_pScene->addItem(pV);
        //QGraphicsTextItem
        auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV);
        auto pItem=(void*)pTextItem;
        
        auto items=m_pScene->items();
        auto item=(QGraphicsItem*)pItem;
        auto b1=items.contains(item);
        
        auto item2=(QGraphicsItem*)pTextItem;
        auto b2=items.contains(item2);
        
        //QGraphicsSimpleTextItem
        auto pSimpleTextItem=new QGraphicsSimpleTextItem("QGraphicsSimpleTextItem",pV);
        auto pSimpleItem=(void*)pSimpleTextItem;
        
        auto SimpleItems=m_pScene->items();
        auto SimpleItem=(QGraphicsItem*)pSimpleItem;
        auto b3=SimpleItems.contains(SimpleItem);
        
        auto Simpleitem2=(QGraphicsItem*)pSimpleItem;
        auto b4=SimpleItems.contains(Simpleitem2);
        
        int i=0;
        

        }

        jsulmJ JonBJ 2 Replies Last reply
        0
        • K ksz123

          Sorry, it should be this demo
          MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::MainWindow)
          {
          ui->setupUi(this);
          m_pScene=new QGraphicsScene(this);
          m_pView=new QGraphicsView(ui->viewWidget);
          m_pView->setScene(m_pScene);

          m_pView->setWindowTitle("Graphics View");
          m_pView->resize(500, 500);
          
          auto x=new QPixmap(R"(D:\desktop\Data\2D\2.bmp)");
          pV=new QGraphicsPixmapItem(*x);
          m_pScene->addItem(pV);
          //QGraphicsTextItem
          auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV);
          auto pItem=(void*)pTextItem;
          
          auto items=m_pScene->items();
          auto item=(QGraphicsItem*)pItem;
          auto b1=items.contains(item);
          
          auto item2=(QGraphicsItem*)pTextItem;
          auto b2=items.contains(item2);
          
          //QGraphicsSimpleTextItem
          auto pSimpleTextItem=new QGraphicsSimpleTextItem("QGraphicsSimpleTextItem",pV);
          auto pSimpleItem=(void*)pSimpleTextItem;
          
          auto SimpleItems=m_pScene->items();
          auto SimpleItem=(QGraphicsItem*)pSimpleItem;
          auto b3=SimpleItems.contains(SimpleItem);
          
          auto Simpleitem2=(QGraphicsItem*)pSimpleItem;
          auto b4=SimpleItems.contains(Simpleitem2);
          
          int i=0;
          

          }

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #5

          @ksz123 said in QGraphicsTextItem * and void * conversion error:

          it should be this demo

          What should be in this demo?
          Please switch to proper C++ casts and tell us how you know that item != item2.

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          K 1 Reply Last reply
          0
          • K Offline
            K Offline
            ksz123
            wrote on last edited by
            #6

            Because in the initial submission, I was trying to bypass this bug. Secondly, using reinterpret_cast did not improve, and finally, in auto bFlag=item==item2; The value of bFlag is false
            //QGraphicsTextItem
            auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV);
            auto pItem=reinterpret_cast<void*>(pTextItem);

            auto items=m_pScene->items();
            auto item=reinterpret_cast<QGraphicsItem*>(pItem);
            auto b1=items.contains(item);
            
            auto item2=dynamic_cast<QGraphicsItem*>(pTextItem);
            auto b2=items.contains(item2);
            
            auto bFlag=item==item2;
            
            1 Reply Last reply
            0
            • jsulmJ jsulm

              @ksz123 said in QGraphicsTextItem * and void * conversion error:

              it should be this demo

              What should be in this demo?
              Please switch to proper C++ casts and tell us how you know that item != item2.

              K Offline
              K Offline
              ksz123
              wrote on last edited by
              #7

              @ChrisW67 said in QGraphicsTextItem * and void * conversion error:

              @ksz123 said in QGraphicsTextItem * and void * conversion error:

              I want to use void * to store the pointer of the QGraphicsTextItem object created, and in another function, convert the void * pointer to a QGraphicsItem pointer

              Why?

              in order to use c style interface

              1 Reply Last reply
              0
              • K ksz123

                Sorry, it should be this demo
                MainWindow::MainWindow(QWidget *parent)
                : QMainWindow(parent)
                , ui(new Ui::MainWindow)
                {
                ui->setupUi(this);
                m_pScene=new QGraphicsScene(this);
                m_pView=new QGraphicsView(ui->viewWidget);
                m_pView->setScene(m_pScene);

                m_pView->setWindowTitle("Graphics View");
                m_pView->resize(500, 500);
                
                auto x=new QPixmap(R"(D:\desktop\Data\2D\2.bmp)");
                pV=new QGraphicsPixmapItem(*x);
                m_pScene->addItem(pV);
                //QGraphicsTextItem
                auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV);
                auto pItem=(void*)pTextItem;
                
                auto items=m_pScene->items();
                auto item=(QGraphicsItem*)pItem;
                auto b1=items.contains(item);
                
                auto item2=(QGraphicsItem*)pTextItem;
                auto b2=items.contains(item2);
                
                //QGraphicsSimpleTextItem
                auto pSimpleTextItem=new QGraphicsSimpleTextItem("QGraphicsSimpleTextItem",pV);
                auto pSimpleItem=(void*)pSimpleTextItem;
                
                auto SimpleItems=m_pScene->items();
                auto SimpleItem=(QGraphicsItem*)pSimpleItem;
                auto b3=SimpleItems.contains(SimpleItem);
                
                auto Simpleitem2=(QGraphicsItem*)pSimpleItem;
                auto b4=SimpleItems.contains(Simpleitem2);
                
                int i=0;
                

                }

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #8

                @ksz123
                Your question/findings are interesting! :)

                Here is a standalone reproducible. Please note that in place of the C cast (void *) I did try reinterpret_cast/static_cast/dynamic_cast and they all behaved the same. I have left it with the C-style cast as that is what the OP asked about, but that is not the issue.

                #include <QApplication>
                #include <QDebug>
                #include <QGraphicsView>
                
                // #define EXTRA_INCLUDES
                
                #ifdef EXTRA_INCLUDES
                #include <QGraphicsSimpleTextItem>
                #include <QGraphicsTextItem>
                #endif
                
                int main(int argc, char *argv[])
                {
                    QApplication a(argc, argv);
                
                    QGraphicsScene scene;
                    QGraphicsView view(&scene);
                
                    QGraphicsSimpleTextItem *simpleTextItem = scene.addSimpleText("Simple Text");
                    QGraphicsItem *graphicsItemForSimpleText = (QGraphicsItem *)simpleTextItem;
                    void *voidSimpleTextItem = (void *)simpleTextItem;
                
                    QGraphicsTextItem *textItem = scene.addText("Text");
                    QGraphicsItem *graphicsItemForText = (QGraphicsItem *)textItem;
                    void *voidTextItem = (void *)textItem;
                
                    QList<QGraphicsItem *>items = scene.items(Qt::AscendingOrder);  // same order as added to scene
                    qDebug() << 1 << items.contains(graphicsItemForSimpleText) << items.contains(voidSimpleTextItem);
                    qDebug() << 2 << items.contains(graphicsItemForText) << items.contains(voidTextItem);
                
                #ifdef EXTRA_INCLUDES
                    QGraphicsItem *first = items.at(0);
                    QGraphicsItem *second = items.at(1);
                    qDebug() << 3 << dynamic_cast<QGraphicsSimpleTextItem *>(first) << dynamic_cast<QGraphicsTextItem *>(second);
                    
                    qDebug() << 4 << (items.at(0) == simpleTextItem) << (items.at(1) == textItem);
                #endif
                    qDebug() << 5 << (items.at(0) == graphicsItemForSimpleText) << (items.at(1) == graphicsItemForText);
                    qDebug() << 6 << (items.at(0) == voidSimpleTextItem) << (items.at(1) == voidTextItem);
                
                    view.show();
                    return a.exec();
                }
                
                

                Running this gives output:

                1 true true
                2 false false
                5 true false
                6 true false
                

                Uncommenting the // #define EXTRA_INCLUDES gives this output:

                1 true true
                2 true false
                3 QGraphicsItem(0x555555759c40, pos=0,0) QGraphicsTextItem(0x55555573c9b0, pos=0,0, flags=(ItemUsesExtendedStyleOption))
                4 true true
                5 true true
                6 true false
                

                In all cases QGraphicsSimpleTextItem * works.

                In both cases for the QGraphicsTextItem * the voidTextItem * gives false. Without the EXTRA_INCLUDES defined graphicsItemForText also gives false, but with the extra includes it gives true. So that is interesting because whether the compiler has the full definition for QGraphicsTextItem or just gets told it's a class QGraphicsTextItem; affects the result.

                I suspect that the issue is because, while QGraphicsSimpleTextItem is just a QAbstractGraphicsShapeItem which is a QAbstractGraphicsShapeItem (single inheritance), QGraphicsTextItem is a QGraphicsTextItem which is a public QObject, public QGraphicsItem which is multiple inheritance. And I am guessing something goes wrong/gets lost when that is cast to void *.

                Note also how from output 3 a QGraphicsSimpleTextItem "degrades" to a QGraphicsItem but a QGraphicsTextItem does not and stays "as-is". This too will (I think) be related to QGraphicsTextItem being "more than just" a QGraphicsItem because it is a QObject too.

                I think this is interesting enough to call on one of out true C++ experts. I invite you to try this standalone code and let us know how you understand the issue of void * as it relates to QGraphicsTextItem, please? :)

                Christian EhrlicherC I 2 Replies Last reply
                1
                • JonBJ JonB

                  @ksz123
                  Your question/findings are interesting! :)

                  Here is a standalone reproducible. Please note that in place of the C cast (void *) I did try reinterpret_cast/static_cast/dynamic_cast and they all behaved the same. I have left it with the C-style cast as that is what the OP asked about, but that is not the issue.

                  #include <QApplication>
                  #include <QDebug>
                  #include <QGraphicsView>
                  
                  // #define EXTRA_INCLUDES
                  
                  #ifdef EXTRA_INCLUDES
                  #include <QGraphicsSimpleTextItem>
                  #include <QGraphicsTextItem>
                  #endif
                  
                  int main(int argc, char *argv[])
                  {
                      QApplication a(argc, argv);
                  
                      QGraphicsScene scene;
                      QGraphicsView view(&scene);
                  
                      QGraphicsSimpleTextItem *simpleTextItem = scene.addSimpleText("Simple Text");
                      QGraphicsItem *graphicsItemForSimpleText = (QGraphicsItem *)simpleTextItem;
                      void *voidSimpleTextItem = (void *)simpleTextItem;
                  
                      QGraphicsTextItem *textItem = scene.addText("Text");
                      QGraphicsItem *graphicsItemForText = (QGraphicsItem *)textItem;
                      void *voidTextItem = (void *)textItem;
                  
                      QList<QGraphicsItem *>items = scene.items(Qt::AscendingOrder);  // same order as added to scene
                      qDebug() << 1 << items.contains(graphicsItemForSimpleText) << items.contains(voidSimpleTextItem);
                      qDebug() << 2 << items.contains(graphicsItemForText) << items.contains(voidTextItem);
                  
                  #ifdef EXTRA_INCLUDES
                      QGraphicsItem *first = items.at(0);
                      QGraphicsItem *second = items.at(1);
                      qDebug() << 3 << dynamic_cast<QGraphicsSimpleTextItem *>(first) << dynamic_cast<QGraphicsTextItem *>(second);
                      
                      qDebug() << 4 << (items.at(0) == simpleTextItem) << (items.at(1) == textItem);
                  #endif
                      qDebug() << 5 << (items.at(0) == graphicsItemForSimpleText) << (items.at(1) == graphicsItemForText);
                      qDebug() << 6 << (items.at(0) == voidSimpleTextItem) << (items.at(1) == voidTextItem);
                  
                      view.show();
                      return a.exec();
                  }
                  
                  

                  Running this gives output:

                  1 true true
                  2 false false
                  5 true false
                  6 true false
                  

                  Uncommenting the // #define EXTRA_INCLUDES gives this output:

                  1 true true
                  2 true false
                  3 QGraphicsItem(0x555555759c40, pos=0,0) QGraphicsTextItem(0x55555573c9b0, pos=0,0, flags=(ItemUsesExtendedStyleOption))
                  4 true true
                  5 true true
                  6 true false
                  

                  In all cases QGraphicsSimpleTextItem * works.

                  In both cases for the QGraphicsTextItem * the voidTextItem * gives false. Without the EXTRA_INCLUDES defined graphicsItemForText also gives false, but with the extra includes it gives true. So that is interesting because whether the compiler has the full definition for QGraphicsTextItem or just gets told it's a class QGraphicsTextItem; affects the result.

                  I suspect that the issue is because, while QGraphicsSimpleTextItem is just a QAbstractGraphicsShapeItem which is a QAbstractGraphicsShapeItem (single inheritance), QGraphicsTextItem is a QGraphicsTextItem which is a public QObject, public QGraphicsItem which is multiple inheritance. And I am guessing something goes wrong/gets lost when that is cast to void *.

                  Note also how from output 3 a QGraphicsSimpleTextItem "degrades" to a QGraphicsItem but a QGraphicsTextItem does not and stays "as-is". This too will (I think) be related to QGraphicsTextItem being "more than just" a QGraphicsItem because it is a QObject too.

                  I think this is interesting enough to call on one of out true C++ experts. I invite you to try this standalone code and let us know how you understand the issue of void * as it relates to QGraphicsTextItem, please? :)

                  Christian EhrlicherC Offline
                  Christian EhrlicherC Offline
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on last edited by Christian Ehrlicher
                  #9

                  @JonB said in QGraphicsTextItem * and void * conversion error:

                  This too will (I think) be related to QGraphicsTextItem being "more than just" a QGraphicsItem because it is a QObject too.

                  Which more or less means that these two classes are 'behind' each other in memory and only the c++ casts know how to do things right since it's c++ and not c.

                  Don't use c style casts, esp. not when working with objects.

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  JonBJ 1 Reply Last reply
                  1
                  • Christian EhrlicherC Christian Ehrlicher

                    @JonB said in QGraphicsTextItem * and void * conversion error:

                    This too will (I think) be related to QGraphicsTextItem being "more than just" a QGraphicsItem because it is a QObject too.

                    Which more or less means that these two classes are 'behind' each other in memory and only the c++ casts know how to do things right since it's c++ and not c.

                    Don't use c style casts, esp. not when working with objects.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #10

                    @Christian-Ehrlicher said in QGraphicsTextItem * and void * conversion error:

                    and only the c++ casts know how to do things right since it's c++ and not c.

                    Whilst I do not disagree that dropping to C/C casts may be problematic, since I wrote/claim above

                    Please note that in place of the C cast (void *) I did try reinterpret_cast/static_cast/dynamic_cast and they all behaved the same. I have left it with the C-style cast as that is what the OP asked about, but that is not the issue.

                    would you be kind enough to spend a few minutes changing the code in whatever way you like for C++ casts which then "gets things right", as I was unable to do so.... Please, I should like to see how it can be made to work because in my findings I could not, maybe you will do something I did not which will make it work. We are talking about the void * case, I cannot get that to work even with C++ casting. In which case I would like an explanation of how it is void * casting rather than C vs C++ casting that is the issue. Thank you.

                    @ksz123
                    While I still hope to hear exactly why casting to void * messes up, the upshot is going to be that, whether you try C or C++ casting, casting to void * is not going to work. You would only want/need to do that from C. But you clearly need to retain the C++ classes in any casting, so that's not going to work from C (because you cannot declare [I don't mean define] even class Something; to be able to declare Something *something; which you would need, as C won't recognise class.)

                    K 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @ksz123
                      Your question/findings are interesting! :)

                      Here is a standalone reproducible. Please note that in place of the C cast (void *) I did try reinterpret_cast/static_cast/dynamic_cast and they all behaved the same. I have left it with the C-style cast as that is what the OP asked about, but that is not the issue.

                      #include <QApplication>
                      #include <QDebug>
                      #include <QGraphicsView>
                      
                      // #define EXTRA_INCLUDES
                      
                      #ifdef EXTRA_INCLUDES
                      #include <QGraphicsSimpleTextItem>
                      #include <QGraphicsTextItem>
                      #endif
                      
                      int main(int argc, char *argv[])
                      {
                          QApplication a(argc, argv);
                      
                          QGraphicsScene scene;
                          QGraphicsView view(&scene);
                      
                          QGraphicsSimpleTextItem *simpleTextItem = scene.addSimpleText("Simple Text");
                          QGraphicsItem *graphicsItemForSimpleText = (QGraphicsItem *)simpleTextItem;
                          void *voidSimpleTextItem = (void *)simpleTextItem;
                      
                          QGraphicsTextItem *textItem = scene.addText("Text");
                          QGraphicsItem *graphicsItemForText = (QGraphicsItem *)textItem;
                          void *voidTextItem = (void *)textItem;
                      
                          QList<QGraphicsItem *>items = scene.items(Qt::AscendingOrder);  // same order as added to scene
                          qDebug() << 1 << items.contains(graphicsItemForSimpleText) << items.contains(voidSimpleTextItem);
                          qDebug() << 2 << items.contains(graphicsItemForText) << items.contains(voidTextItem);
                      
                      #ifdef EXTRA_INCLUDES
                          QGraphicsItem *first = items.at(0);
                          QGraphicsItem *second = items.at(1);
                          qDebug() << 3 << dynamic_cast<QGraphicsSimpleTextItem *>(first) << dynamic_cast<QGraphicsTextItem *>(second);
                          
                          qDebug() << 4 << (items.at(0) == simpleTextItem) << (items.at(1) == textItem);
                      #endif
                          qDebug() << 5 << (items.at(0) == graphicsItemForSimpleText) << (items.at(1) == graphicsItemForText);
                          qDebug() << 6 << (items.at(0) == voidSimpleTextItem) << (items.at(1) == voidTextItem);
                      
                          view.show();
                          return a.exec();
                      }
                      
                      

                      Running this gives output:

                      1 true true
                      2 false false
                      5 true false
                      6 true false
                      

                      Uncommenting the // #define EXTRA_INCLUDES gives this output:

                      1 true true
                      2 true false
                      3 QGraphicsItem(0x555555759c40, pos=0,0) QGraphicsTextItem(0x55555573c9b0, pos=0,0, flags=(ItemUsesExtendedStyleOption))
                      4 true true
                      5 true true
                      6 true false
                      

                      In all cases QGraphicsSimpleTextItem * works.

                      In both cases for the QGraphicsTextItem * the voidTextItem * gives false. Without the EXTRA_INCLUDES defined graphicsItemForText also gives false, but with the extra includes it gives true. So that is interesting because whether the compiler has the full definition for QGraphicsTextItem or just gets told it's a class QGraphicsTextItem; affects the result.

                      I suspect that the issue is because, while QGraphicsSimpleTextItem is just a QAbstractGraphicsShapeItem which is a QAbstractGraphicsShapeItem (single inheritance), QGraphicsTextItem is a QGraphicsTextItem which is a public QObject, public QGraphicsItem which is multiple inheritance. And I am guessing something goes wrong/gets lost when that is cast to void *.

                      Note also how from output 3 a QGraphicsSimpleTextItem "degrades" to a QGraphicsItem but a QGraphicsTextItem does not and stays "as-is". This too will (I think) be related to QGraphicsTextItem being "more than just" a QGraphicsItem because it is a QObject too.

                      I think this is interesting enough to call on one of out true C++ experts. I invite you to try this standalone code and let us know how you understand the issue of void * as it relates to QGraphicsTextItem, please? :)

                      I Offline
                      I Offline
                      IgKh
                      wrote on last edited by IgKh
                      #11

                      @JonB said in QGraphicsTextItem * and void * conversion error:

                      I suspect that the issue is because, while QGraphicsSimpleTextItem is just a QAbstractGraphicsShapeItem which is a QAbstractGraphicsShapeItem (single inheritance), QGraphicsTextItem is a QGraphicsTextItem which is a public QObject, public QGraphicsItem which is multiple inheritance. And I am guessing something goes wrong/gets lost when that is cast to void *.

                      You suspect right. Under single inheritance when class B extends class A (which has virtual methods), both class B's vtable and memory layout are simple linear extensions of A's. So an upcast (static_cast explicitly, or what a C++ compiler will turn a C-style cast into) is a no-op as any pointer to B can be safely interepreted as a pointer to A.

                      This is not the case under multiple inheritance, the child class' layout is more complex and divided into "areas" corresponding to the data and vtable of each of its' parents. An upcast is no longer a trivial operation, but has to calculate and return a internal pointer to the right "area" (which is of course different to the memory address of the child object as a whole). This blog post has nice visualization of that.

                      This means that a downcast back to the child class is a complex operation, that requires additional information to replace the information lost in the upcast. A round-trip through void * would need some sort of a sequence of static_cast / dynamic_cast along with reinterpret_cast incantations... and a lot of care in general.

                      1 Reply Last reply
                      2
                      • JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by JonB
                        #12

                        @ksz123

                        P.S.
                        Assuming I am right about it being multiple inheritance (now confirmed by @IgKh, I wrote this before he replied) which makes QGraphicsTextItem fail after being cast to void *, I think this whole issue is covered by/explained in multiple inheritance: unexpected result after cast from void * to 2nd base class from 14 years ago! QGraphicsTextItem derives from QObject first and QGraphicsItem second, hence its layout has QObject in first position.

                        For your case changing over to

                        void *voidTextItem = (void *)(QGraphicsItem *)textItem;
                        

                        does actually make it work! Whether you can do it (it's too late by the time you pass as void * to your code, it has to be done when/before passing the pointer, or you have to know the void * is a QGraphicsTextItem * and cast it back to that and then via QGraphicsItem * to a new void * value, and you won't be able to do that from C code you need C++ to access the classes!), and whether you really should abandon your C casts and trying to run stuff from C, is another matter....

                        [To be clear: if you really want to make this work via void * from C, you must pass the original QGraphicsTextItem *textItem via (QGraphicsItem *)textItem or equivalent from the C++ layer.]

                        I 1 Reply Last reply
                        1
                        • JonBJ JonB

                          @ksz123

                          P.S.
                          Assuming I am right about it being multiple inheritance (now confirmed by @IgKh, I wrote this before he replied) which makes QGraphicsTextItem fail after being cast to void *, I think this whole issue is covered by/explained in multiple inheritance: unexpected result after cast from void * to 2nd base class from 14 years ago! QGraphicsTextItem derives from QObject first and QGraphicsItem second, hence its layout has QObject in first position.

                          For your case changing over to

                          void *voidTextItem = (void *)(QGraphicsItem *)textItem;
                          

                          does actually make it work! Whether you can do it (it's too late by the time you pass as void * to your code, it has to be done when/before passing the pointer, or you have to know the void * is a QGraphicsTextItem * and cast it back to that and then via QGraphicsItem * to a new void * value, and you won't be able to do that from C code you need C++ to access the classes!), and whether you really should abandon your C casts and trying to run stuff from C, is another matter....

                          [To be clear: if you really want to make this work via void * from C, you must pass the original QGraphicsTextItem *textItem via (QGraphicsItem *)textItem or equivalent from the C++ layer.]

                          I Offline
                          I Offline
                          IgKh
                          wrote on last edited by
                          #13

                          @JonB said in QGraphicsTextItem * and void * conversion error:

                          For your case changing over to

                          void *voidTextItem = (void *)(QGraphicsItem *)textItem;

                          Yep, that would a sequence of incantations. Or in C++ speak:

                          void *voidTextItem = reinterpret_cast<void*>(static_cast<QGraphicsItem*>(textItem))

                          In general - when a C++ compiler encounters a C-style cast, it will convert it into one of the C++ cast types: static_cast, const_cast, dynamic_cast or reinterpret_cast based on what it knows about the relationship between the source and target types. The reason everyone keeps repeating the advice not to use C-style casts in C++ code is because "what the compiler knows about the types" is context dependent and can be surprising (e.g as @JonB has shown, whether there is only a forward declaration or the full definition changes the cast type). Since casts can actually involve machine code being emitted which radically changes the result, being explicit about the cast type is very important.

                          1 Reply Last reply
                          2
                          • JonBJ JonB

                            @Christian-Ehrlicher said in QGraphicsTextItem * and void * conversion error:

                            and only the c++ casts know how to do things right since it's c++ and not c.

                            Whilst I do not disagree that dropping to C/C casts may be problematic, since I wrote/claim above

                            Please note that in place of the C cast (void *) I did try reinterpret_cast/static_cast/dynamic_cast and they all behaved the same. I have left it with the C-style cast as that is what the OP asked about, but that is not the issue.

                            would you be kind enough to spend a few minutes changing the code in whatever way you like for C++ casts which then "gets things right", as I was unable to do so.... Please, I should like to see how it can be made to work because in my findings I could not, maybe you will do something I did not which will make it work. We are talking about the void * case, I cannot get that to work even with C++ casting. In which case I would like an explanation of how it is void * casting rather than C vs C++ casting that is the issue. Thank you.

                            @ksz123
                            While I still hope to hear exactly why casting to void * messes up, the upshot is going to be that, whether you try C or C++ casting, casting to void * is not going to work. You would only want/need to do that from C. But you clearly need to retain the C++ classes in any casting, so that's not going to work from C (because you cannot declare [I don't mean define] even class Something; to be able to declare Something *something; which you would need, as C won't recognise class.)

                            K Offline
                            K Offline
                            ksz123
                            wrote on last edited by
                            #14

                            Thank you all for your help. Based on your analysis, here is my solution,
                            Create section

                            auto pTextItem=new QGraphicsTextItem("QGraphicsTextItem",pV); 
                            auto id=reinterpret_cast<void*>(dynamic_cast<QGraphicsItem*>(pTextItem)); 
                            

                            deletion

                            void DeleteGraphics(void* id)
                            {
                                if (id==nullptr)
                                    return;
                            
                                auto scene=m_pQGraphicsView->scene();
                                auto items=scene->items();
                                QGraphicsItem* item = static_cast<QGraphicsItem*>(id);
                                if(items.contains(item)){
                                    scene->removeItem(item);
                                    delete item;
                                }
                            }
                            
                            1 Reply Last reply
                            0
                            • JonBJ JonB referenced this topic on

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved