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. Wrapping non-Qt code
Forum Updated to NodeBB v4.3 + New Features

Wrapping non-Qt code

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 3 Posters 318 Views 2 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.
  • S Offline
    S Offline
    SummoningDark
    wrote on last edited by
    #1

    I have a library on non-Qt code that I would like to add signals to so I can use it in a Qt application easily.

    An issue is that my library code is templated, so I can't directly derive from QObject with my wrappers. I fixed this by making a class that derives from QObject that just defines signals/slots, and a second (templated) class that derives from both my signal class and the library code. This also works.

    The problem come in because my library is "layered" ie there is a base class and several derived classes. I would like to wrap each derived class in the library separately and not duplicate code. However this leads to a sort of double diamond inheritance problem.

    My simple example project is 99% there. however my Qt wrappers can't access the signals of the parent Qt wrappers (right now this is expected since they don't derive from them, as this brings on the double diamond inheritance problem)

    To the TLDR version is can I make wrappers for a set of templated classes such that each derived class has a wrapper that wraps its functionality, and each wrapper also gives access to the (wrapped) parent class methods.

    here is a simple example that shows what I'm trying to do. I haven't figured out how to attach zip files (maybe it isn't possible) but other than the .ui and .pro files this is pretty much the whole project:

    Non-Qt classes (usually in separate header files)

    template<typename T>
    class nonQtBase
    {
    public:
        nonQtBase(T init)
        {
            value = init;
        }
    
        virtual T funcAdd(T first, T second)
        {
            value = first + second;
            return value;
        }
    
        T getValue()
        {
            return value;
        }
    
    protected:
        T value;
    };
    
    template<typename T>
    class nonQtDrv1 : public nonQtBase<T>
    {
    public:
        nonQtDrv1(T init) : nonQtBase<T>(init)
        {
    
        }
    
        virtual T funcSub(T first, T second)
        {
            this->value = first - second;
            return this->value;
        }
    };
    
    template<typename T>
    class nonQtDrv2 : public nonQtDrv1<T>
    {
    public:
        nonQtDrv2(T init) : nonQtDrv1<T>(init)
        {
    
        }
    
        virtual T funcMult(T first, T second)
        {
            this->value = first * second;
            return this->value;
        }
    };
    
    

    Qt wrappers (also usually in separate header files)

    class QtBaseSignals : public QObject
    {
        Q_OBJECT
    public:
        explicit QtBaseSignals(QObject *parent=nullptr) : QObject(parent)
        {
    
        }
    
    signals:
        void sigAddResult(QString);
    };
    
    template<typename T>
    class QtBase : public QtBaseSignals, public nonQtBase<T>
    {
    public:
        QtBase(T init, QObject *parent = nullptr) : QtBaseSignals(parent), nonQtBase<T>(init)
        {
    
        }
    
        // This function wrapps the non-Qt function to emit a signal
        virtual T funcAdd(T first, T second)
        {
            T result = nonQtBase<T>::funcAdd(first, second);
            emit sigAddResult(QString::number(result));
            return result;
        }
    };
    
    class QtDrv1Signals : public QtBaseSignals
    {
        Q_OBJECT
    public:
        explicit QtDrv1Signals(QObject *parent=nullptr) : QtBaseSignals(parent)
        {
    
        }
    
    signals:
        void sigSubResult(QString);
    };
    
    template<typename T>
    class QtDrv1 : public QtDrv1Signals, public nonQtDrv1<T>
    {
    public:
        QtDrv1(T init, QObject *parent = nullptr) : QtDrv1Signals(parent), nonQtDrv1<T>(init)
        {
    
        }
        
        // challenge is to somehow access the wrapper for the
        // base function "QtBase::funcAdd" without re-implementing
        // it here and without breaking everything with multiple inheritance.
    
        // another wrapper. for a method in the first derived class
        virtual T funcSub(T first, T second)
        {
            T result = nonQtDrv1<T>::funcSub(first, second);
            emit sigSubResult(QString::number(result));
            return result;
        }
    };
    
    class QtDrv2Signals : public QtDrv1Signals
    {
        Q_OBJECT
    public:
        explicit QtDrv2Signals(QObject *parent=nullptr) : QtDrv1Signals(parent)
        {
    
        }
    
    signals:
        void sigMultResult(QString);
    };
    
    template<typename T>
    class QtDrv2 : public QtDrv2Signals, public nonQtDrv2<T>
    {
    public:
        QtDrv2(T init, QObject *parent = nullptr) : QtDrv2Signals(parent), nonQtDrv2<T>(init)
        {
    
        }
    
        virtual T funcMult(T first, T second)
        {
            T result = nonQtDrv2<T>::funcMult(first, second);
            emit sigMultResult(QString::number(result));
            return result;
        }
    };
    

    My main window header:

    #include <QMainWindow>
    #include "qtdrv2.h"
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private slots:
        void on_nonBaseAdd_clicked();
    
        void on_nonD1Add_clicked();
    
        void on_nonD1Sub_clicked();
    
        void on_nonD2Add_clicked();
    
        void on_nonD2Sub_clicked();
    
        void on_nonD2Mult_clicked();
    
        void on_qtBaseAdd_clicked();
    
        void on_qtD1Add_clicked();
    
        void on_qtD1Sub_clicked();
    
        void on_qtD2Add_clicked();
    
        void on_qtD2Sub_clicked();
    
        void on_qtD2Mult_clicked();
    
    private:
        Ui::MainWindow *ui;
    
        nonQtBase<int> nonQtBaseInt;
        nonQtDrv1<int> nonQtDrv1Int;
        nonQtDrv2<int> nonQtDrv2Int;
    
        QtBase<int> qtBaseInt;
        QtDrv1<int> qtDrv1Int;
        QtDrv2<int> qtDrv2Int;
    };
    

    My main window code

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent):
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        nonQtBaseInt(0),
        nonQtDrv1Int(0),
        nonQtDrv2Int(0),
        qtBaseInt(0),
        qtDrv1Int(0),
        qtDrv2Int(0)
    {
        ui->setupUi(this);    
    
        // connect all the signals for the QtWrappers
        connect(&qtBaseInt, SIGNAL(sigAddResult(QString)), ui->qtBaseResult, SLOT(setText(QString)));
        connect(&qtDrv1Int, SIGNAL(sigAddResult(QString)), ui->qtD1Result, SLOT(setText(QString)));
        connect(&qtDrv1Int, SIGNAL(sigSubResult(QString)), ui->qtD1Result, SLOT(setText(QString)));
        connect(&qtDrv2Int, SIGNAL(sigAddResult(QString)), ui->qtD2Result, SLOT(setText(QString)));
        connect(&qtDrv2Int, SIGNAL(sigSubResult(QString)), ui->qtD2Result, SLOT(setText(QString)));
        connect(&qtDrv2Int, SIGNAL(sigMultResult(QString)), ui->qtD2Result, SLOT(setText(QString)));
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    void MainWindow::on_nonBaseAdd_clicked()
    {
        nonQtBaseInt.funcAdd(ui->nonBaseFirst->value(), ui->nonBaseSecond->value());
        ui->nonBaseResult->setText(QString::number(nonQtBaseInt.getValue()));
    }
    
    
    void MainWindow::on_nonD1Add_clicked()
    {
        nonQtDrv1Int.funcAdd(ui->nonD1First->value(), ui->nonD1Second->value());
        ui->nonD1Result->setText(QString::number(nonQtDrv1Int.getValue()));
    }
    
    
    void MainWindow::on_nonD1Sub_clicked()
    {
        nonQtDrv1Int.funcSub(ui->nonD1First->value(), ui->nonD1Second->value());
        ui->nonD1Result->setText(QString::number(nonQtDrv1Int.getValue()));
    }
    
    
    void MainWindow::on_nonD2Add_clicked()
    {
        nonQtDrv2Int.funcAdd(ui->nonD2First->value(), ui->nonD2Second->value());
        ui->nonD2Result->setText(QString::number(nonQtDrv2Int.getValue()));
    }
    
    
    void MainWindow::on_nonD2Sub_clicked()
    {
        nonQtDrv2Int.funcSub(ui->nonD2First->value(), ui->nonD2Second->value());
        ui->nonD2Result->setText(QString::number(nonQtDrv2Int.getValue()));
    }
    
    
    void MainWindow::on_nonD2Mult_clicked()
    {
        nonQtDrv2Int.funcMult(ui->nonD2First->value(), ui->nonD2Second->value());
        ui->nonD2Result->setText(QString::number(nonQtDrv2Int.getValue()));
    }
    
    
    void MainWindow::on_qtBaseAdd_clicked()
    {
        qtBaseInt.funcAdd(ui->qtBaseFirst->value(), ui->qtBaseSecond->value());
    }
    
    
    void MainWindow::on_qtD1Add_clicked()
    {
        qtDrv1Int.funcAdd(ui->qtD1First->value(), ui->qtD1Second->value());
    }
    
    
    void MainWindow::on_qtD1Sub_clicked()
    {
        qtDrv1Int.funcSub(ui->qtD1First->value(), ui->qtD1Second->value());
    }
    
    
    void MainWindow::on_qtD2Add_clicked()
    {
        qtDrv2Int.funcAdd(ui->qtD2First->value(), ui->qtD2Second->value());
    }
    
    
    void MainWindow::on_qtD2Sub_clicked()
    {
        qtDrv2Int.funcSub(ui->qtD2First->value(), ui->qtD2Second->value());
    }
    
    
    
    void MainWindow::on_qtD2Mult_clicked()
    {
        qtDrv2Int.funcMult(ui->qtD2First->value(), ui->qtD2Second->value());
    }
    
    Pl45m4P 1 Reply Last reply
    0
    • S SummoningDark

      I have a library on non-Qt code that I would like to add signals to so I can use it in a Qt application easily.

      An issue is that my library code is templated, so I can't directly derive from QObject with my wrappers. I fixed this by making a class that derives from QObject that just defines signals/slots, and a second (templated) class that derives from both my signal class and the library code. This also works.

      The problem come in because my library is "layered" ie there is a base class and several derived classes. I would like to wrap each derived class in the library separately and not duplicate code. However this leads to a sort of double diamond inheritance problem.

      My simple example project is 99% there. however my Qt wrappers can't access the signals of the parent Qt wrappers (right now this is expected since they don't derive from them, as this brings on the double diamond inheritance problem)

      To the TLDR version is can I make wrappers for a set of templated classes such that each derived class has a wrapper that wraps its functionality, and each wrapper also gives access to the (wrapped) parent class methods.

      here is a simple example that shows what I'm trying to do. I haven't figured out how to attach zip files (maybe it isn't possible) but other than the .ui and .pro files this is pretty much the whole project:

      Non-Qt classes (usually in separate header files)

      template<typename T>
      class nonQtBase
      {
      public:
          nonQtBase(T init)
          {
              value = init;
          }
      
          virtual T funcAdd(T first, T second)
          {
              value = first + second;
              return value;
          }
      
          T getValue()
          {
              return value;
          }
      
      protected:
          T value;
      };
      
      template<typename T>
      class nonQtDrv1 : public nonQtBase<T>
      {
      public:
          nonQtDrv1(T init) : nonQtBase<T>(init)
          {
      
          }
      
          virtual T funcSub(T first, T second)
          {
              this->value = first - second;
              return this->value;
          }
      };
      
      template<typename T>
      class nonQtDrv2 : public nonQtDrv1<T>
      {
      public:
          nonQtDrv2(T init) : nonQtDrv1<T>(init)
          {
      
          }
      
          virtual T funcMult(T first, T second)
          {
              this->value = first * second;
              return this->value;
          }
      };
      
      

      Qt wrappers (also usually in separate header files)

      class QtBaseSignals : public QObject
      {
          Q_OBJECT
      public:
          explicit QtBaseSignals(QObject *parent=nullptr) : QObject(parent)
          {
      
          }
      
      signals:
          void sigAddResult(QString);
      };
      
      template<typename T>
      class QtBase : public QtBaseSignals, public nonQtBase<T>
      {
      public:
          QtBase(T init, QObject *parent = nullptr) : QtBaseSignals(parent), nonQtBase<T>(init)
          {
      
          }
      
          // This function wrapps the non-Qt function to emit a signal
          virtual T funcAdd(T first, T second)
          {
              T result = nonQtBase<T>::funcAdd(first, second);
              emit sigAddResult(QString::number(result));
              return result;
          }
      };
      
      class QtDrv1Signals : public QtBaseSignals
      {
          Q_OBJECT
      public:
          explicit QtDrv1Signals(QObject *parent=nullptr) : QtBaseSignals(parent)
          {
      
          }
      
      signals:
          void sigSubResult(QString);
      };
      
      template<typename T>
      class QtDrv1 : public QtDrv1Signals, public nonQtDrv1<T>
      {
      public:
          QtDrv1(T init, QObject *parent = nullptr) : QtDrv1Signals(parent), nonQtDrv1<T>(init)
          {
      
          }
          
          // challenge is to somehow access the wrapper for the
          // base function "QtBase::funcAdd" without re-implementing
          // it here and without breaking everything with multiple inheritance.
      
          // another wrapper. for a method in the first derived class
          virtual T funcSub(T first, T second)
          {
              T result = nonQtDrv1<T>::funcSub(first, second);
              emit sigSubResult(QString::number(result));
              return result;
          }
      };
      
      class QtDrv2Signals : public QtDrv1Signals
      {
          Q_OBJECT
      public:
          explicit QtDrv2Signals(QObject *parent=nullptr) : QtDrv1Signals(parent)
          {
      
          }
      
      signals:
          void sigMultResult(QString);
      };
      
      template<typename T>
      class QtDrv2 : public QtDrv2Signals, public nonQtDrv2<T>
      {
      public:
          QtDrv2(T init, QObject *parent = nullptr) : QtDrv2Signals(parent), nonQtDrv2<T>(init)
          {
      
          }
      
          virtual T funcMult(T first, T second)
          {
              T result = nonQtDrv2<T>::funcMult(first, second);
              emit sigMultResult(QString::number(result));
              return result;
          }
      };
      

      My main window header:

      #include <QMainWindow>
      #include "qtdrv2.h"
      
      QT_BEGIN_NAMESPACE
      namespace Ui { class MainWindow; }
      QT_END_NAMESPACE
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          MainWindow(QWidget *parent = nullptr);
          ~MainWindow();
      
      private slots:
          void on_nonBaseAdd_clicked();
      
          void on_nonD1Add_clicked();
      
          void on_nonD1Sub_clicked();
      
          void on_nonD2Add_clicked();
      
          void on_nonD2Sub_clicked();
      
          void on_nonD2Mult_clicked();
      
          void on_qtBaseAdd_clicked();
      
          void on_qtD1Add_clicked();
      
          void on_qtD1Sub_clicked();
      
          void on_qtD2Add_clicked();
      
          void on_qtD2Sub_clicked();
      
          void on_qtD2Mult_clicked();
      
      private:
          Ui::MainWindow *ui;
      
          nonQtBase<int> nonQtBaseInt;
          nonQtDrv1<int> nonQtDrv1Int;
          nonQtDrv2<int> nonQtDrv2Int;
      
          QtBase<int> qtBaseInt;
          QtDrv1<int> qtDrv1Int;
          QtDrv2<int> qtDrv2Int;
      };
      

      My main window code

      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      
      MainWindow::MainWindow(QWidget *parent):
          QMainWindow(parent),
          ui(new Ui::MainWindow),
          nonQtBaseInt(0),
          nonQtDrv1Int(0),
          nonQtDrv2Int(0),
          qtBaseInt(0),
          qtDrv1Int(0),
          qtDrv2Int(0)
      {
          ui->setupUi(this);    
      
          // connect all the signals for the QtWrappers
          connect(&qtBaseInt, SIGNAL(sigAddResult(QString)), ui->qtBaseResult, SLOT(setText(QString)));
          connect(&qtDrv1Int, SIGNAL(sigAddResult(QString)), ui->qtD1Result, SLOT(setText(QString)));
          connect(&qtDrv1Int, SIGNAL(sigSubResult(QString)), ui->qtD1Result, SLOT(setText(QString)));
          connect(&qtDrv2Int, SIGNAL(sigAddResult(QString)), ui->qtD2Result, SLOT(setText(QString)));
          connect(&qtDrv2Int, SIGNAL(sigSubResult(QString)), ui->qtD2Result, SLOT(setText(QString)));
          connect(&qtDrv2Int, SIGNAL(sigMultResult(QString)), ui->qtD2Result, SLOT(setText(QString)));
      
      }
      
      MainWindow::~MainWindow()
      {
          delete ui;
      }
      
      
      void MainWindow::on_nonBaseAdd_clicked()
      {
          nonQtBaseInt.funcAdd(ui->nonBaseFirst->value(), ui->nonBaseSecond->value());
          ui->nonBaseResult->setText(QString::number(nonQtBaseInt.getValue()));
      }
      
      
      void MainWindow::on_nonD1Add_clicked()
      {
          nonQtDrv1Int.funcAdd(ui->nonD1First->value(), ui->nonD1Second->value());
          ui->nonD1Result->setText(QString::number(nonQtDrv1Int.getValue()));
      }
      
      
      void MainWindow::on_nonD1Sub_clicked()
      {
          nonQtDrv1Int.funcSub(ui->nonD1First->value(), ui->nonD1Second->value());
          ui->nonD1Result->setText(QString::number(nonQtDrv1Int.getValue()));
      }
      
      
      void MainWindow::on_nonD2Add_clicked()
      {
          nonQtDrv2Int.funcAdd(ui->nonD2First->value(), ui->nonD2Second->value());
          ui->nonD2Result->setText(QString::number(nonQtDrv2Int.getValue()));
      }
      
      
      void MainWindow::on_nonD2Sub_clicked()
      {
          nonQtDrv2Int.funcSub(ui->nonD2First->value(), ui->nonD2Second->value());
          ui->nonD2Result->setText(QString::number(nonQtDrv2Int.getValue()));
      }
      
      
      void MainWindow::on_nonD2Mult_clicked()
      {
          nonQtDrv2Int.funcMult(ui->nonD2First->value(), ui->nonD2Second->value());
          ui->nonD2Result->setText(QString::number(nonQtDrv2Int.getValue()));
      }
      
      
      void MainWindow::on_qtBaseAdd_clicked()
      {
          qtBaseInt.funcAdd(ui->qtBaseFirst->value(), ui->qtBaseSecond->value());
      }
      
      
      void MainWindow::on_qtD1Add_clicked()
      {
          qtDrv1Int.funcAdd(ui->qtD1First->value(), ui->qtD1Second->value());
      }
      
      
      void MainWindow::on_qtD1Sub_clicked()
      {
          qtDrv1Int.funcSub(ui->qtD1First->value(), ui->qtD1Second->value());
      }
      
      
      void MainWindow::on_qtD2Add_clicked()
      {
          qtDrv2Int.funcAdd(ui->qtD2First->value(), ui->qtD2Second->value());
      }
      
      
      void MainWindow::on_qtD2Sub_clicked()
      {
          qtDrv2Int.funcSub(ui->qtD2First->value(), ui->qtD2Second->value());
      }
      
      
      
      void MainWindow::on_qtD2Mult_clicked()
      {
          qtDrv2Int.funcMult(ui->qtD2First->value(), ui->qtD2Second->value());
      }
      
      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote on last edited by
      #2

      @SummoningDark said in Wrapping non-Qt code:

      To the TLDR version is can I make wrappers for a set of templated classes such that each derived class has a wrapper that wraps its functionality, and each wrapper also gives access to the (wrapped) parent class methods.

      You can't template a QObject. AFAIK moc doesn't support it.


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      1 Reply Last reply
      3
      • S Offline
        S Offline
        SummoningDark
        wrote on last edited by
        #3

        Sorry, I should have been more clear in my summary. Another key is that the signals/slots do not depend on the templating, so they can be separated.

        The following works for a single wrapped class:
        1 create a non-templated class that derives from QObject and defines all the signals and slots(slots defined pure virtual and implemented in the final class)

        2 create the templated wrapper class that derives from both the signal/slot class from 1 and the templated library class. ( this class defines the functionality of the slots )

        This can be seen in the QtBaseSignals/nonQtBase<T>/QtBase<T> in my example code, and works fine as far as I can tell.

        Using virtual inheritance, I can make a derived class that has access to the methods in the first wrapper class. Even adding new slots works by making a second custom signals/slots class. The real issue is that if I create a new signal (in ex. QtDrv1Signals) and try to connect it, I get an error. It seems to be this:

        Cannot convert from pointer to base class to pointer to derived class

        I was hoping that someone had a clever solution. If all else fails, I can re-write the templated code.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SimonSchroeder
          wrote on last edited by
          #4

          You should be using composition instead of inheritance.

          Instead of

          template<typename T>
          class QtBase: public QtBaseSignals, public nonQtBase<T>
          {
          ...
          }
          

          you should write

          template<typename T>
          class QtBase : public QtBaseSignals
          {
            Q_OBJECT // this is totally necessary (don't know if it works with templates...)
            std::unique_ptr<nonQtBase<T>> data;
            ...
          }
          

          This should not be much of a problem as you are wrapping all functions already in order to be able to emit signals.

          The derived class would then also just inherit from the base:

          template<typename T>
          class QtDrv1 : public QtBase
          {
          ...
          }
          

          (You should drop the QtBaseSignals/QtDrv1Signals classes!) QtDrv1 will not have its own data member, but will use the one provided by QtBase. This is the good thing about polymorphism. However, when forwarding signals in your derived Qt classes you should always cast to the derived type, e.g. nonQtDrv1<T>, of data before accessing it.

          1 Reply Last reply
          3

          • Login

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