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 678 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 Offline
    K Offline
    ksz123
    wrote on last edited by
    #1

    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 C 2 Replies 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;
      }
      
      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 Online
                        I Online
                        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 Online
                            I Online
                            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