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

  • 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?

  • Moderators

    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
        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
        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
        ConcreteDevice1(QObject* parent = nullptr) : AbstractDevice(parent) {}
        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
        WorkManager(QObject* parent  = nullptr) : QThread(parent) {}
        void scheduleJob(AbstractDevice* worker) {
            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
        WorkerFactory(QObject* parent = nullptr) : QObject(parent) {}
        template<typename T>
        void registerWorkerType(WorkType type) { types[type] = makeDevice<T>; }
        AbstractDevice* createWorker(WorkType type, QObject* parent = nullptr) { return types[type](parent); }
        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;

    Create the worker thread manager and start the thread:

    WorkManager mgr;

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


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

    auto worker = factory.createWorker(WorkType::OtherStuff);
    //you can connect to some extra signals of the worker here if it has any

  • wow! its beautiful! )

Log in to reply

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.