Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. its just a quiz... (for me at least)

its just a quiz... (for me at least)

Scheduled Pinned Locked Moved Solved C++ Gurus
3 Posts 2 Posters 1.4k 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.
  • Stanislav SilnickiS Offline
    Stanislav SilnickiS Offline
    Stanislav Silnicki
    wrote on last edited by
    #1

    Hello!

    What I want to do, could be done many ways, I suppose....
    Anyway, say, I'm gonna init some worker thread, leaving GUI thread's widgets signal-slot connected with object, that will do all job inside newly created thread. This object, call it AbstractDevice, has to behave differentially, depending upon argument, I pass to the constructor. So, the implementation has to be split into separate classes, derived from AbstractDevice. And here is the quiz: I don't want to care about which ParticularDevice implementation will do the job, when I instantiate it. They all will have the same signals&slots interface, derived from AbstractDevice. Is it possible to do?

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #2

      As you said - it can be done many ways.
      To me it sounds like a classic factory + worker scenario, so here's a brief. Keep in mind I'm leaving stuff like error checking out for brevity.

      First create the worker interface. For example:

      class AbstractDevice : public QObject
      {
          Q_OBJECT
      public:
          AbstractDevice(QObject* parent = nullptr) : QObject(parent) {
              connect(this, &AbstractDevice::finished, this, &AbstractDevice::deleteLater); //auto destruction
          }
      public slots:
          virtual void doWork() = 0; //this is the interface that actual workers will implement
      
      signals:
          void finished() const; //something to let the world know when the work is done
      };
      

      Then implement some concrete workers, e.g.

      class ConcreteDevice1 : public AbstractDevice
      {
      public:
          using AbstractDevice::AbstractDevice;
          void doWork() override { qDebug() << "CD1 working"; emit finished(); }
      };
      

      Next, you said that the type of work to do will depend on some argument, so lets define these types. Could be anything but I'll use enum for simplicity:

      enum WorkType { Stuff, OtherStuff };
      

      We need a worker thread to run the tasks, so here's a very minimal implementation:

      class WorkManager : public QThread
      {
      public:
          using QThread::QThread;
      
          void scheduleJob(AbstractDevice* worker) {
              worker->moveToThread(this);
              worker->metaObject()->invokeMethod(worker, "doWork"); //call the slot in the worker thread
          }
      };
      

      Last thing of your requirements is that at call site you don't want to know the class of worker that will do the job. So lets make a basic factory that will take care of that:

      class WorkerFactory : public QObject
      {
          Q_OBJECT
      public:
          using QObject::QObject;
      
          template<typename T>
          void registerWorkerType(WorkType type) { types[type] = makeDevice<T>; }
      
          AbstractDevice* createWorker(WorkType type, QObject* parent = nullptr) { return types[type](parent); }
      
      private:
          template <typename T>
          static AbstractDevice* makeDevice(QObject* parent) { return new T(parent); }
      
          QMap<WorkType, AbstractDevice*(*)(QObject*)> types;
      };
      

      Right, all the pieces are in place, now you can use them.
      Create an instance of the factory and register all the workers:

      WorkerFactory factory;
      factory.registerWorkerType<ConcreteDevice1>(WorkType::Stuff);
      factory.registerWorkerType<ConcreteDevice2>(WorkType::OtherStuff);
      

      Create the worker thread manager and start the thread:

      WorkManager mgr;
      mgr.start();
      

      Don't forget to stop it when your app is done:

      mgr.quit();
      mgr.wait();
      

      Now, when you need some job done all you do is create a worker and schedule it:

      auto worker = factory.createWorker(WorkType::OtherStuff);
      mgr.scheduleJob(worker);
      //you can connect to some extra signals of the worker here if it has any
      
      1 Reply Last reply
      6
      • Stanislav SilnickiS Offline
        Stanislav SilnickiS Offline
        Stanislav Silnicki
        wrote on last edited by
        #3

        wow! its beautiful! )

        1 Reply Last reply
        1

        • Login

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