0

I have an interface QInterruptable as follows:

#ifndef QINTERRUPTABLE_H
#define QINTERRUPTABLE_H

class QInterruptable {
public:
    virtual void pause();
    virtual void resume();
    virtual void interrupt();
    virtual ~QInterruptable(){

    }
};

#endif // QINTERRUPTABLE_H

An example use of QInterruptable is in sub-classing a QThread WorkerObject for additional functionality.

QInterruptable is used in my ThreadWorker header file

#ifndef THREADWORKER_H
#define THREADWORKER_H

#include <QObject>
#include <functional>
#include <QWaitCondition>
#include <QMutex>

#include "QInterruptable.h"

class ThreadWorker : public QObject, public QInterruptable
{
    Q_OBJECT

private:
    QMutex mutex;
    QWaitCondition *waitCondition;
    std::function<void ()> runnable;
    bool shouldPause = false;

public:
    explicit ThreadWorker(QObject *parent = nullptr);
    ThreadWorker(std::function<void ()> func);
    ~ThreadWorker();

    void setRunnable(const std::function<void ()> &value);

signals:
    void started();
    void progress(int value);
    void finished();
    void error();

public slots:
    virtual void run();
    virtual void cleanup();

    // QInterruptable interface
public:
    void pause()
    {
        shouldPause = true;
    }
    void resume()
    {
        shouldPause = false;
    }
    void interrupt()
    {

    }

    QMutex& getMutex();
    QWaitCondition *getWaitCondition() const;
    void setWaitCondition(QWaitCondition *value);
    bool getShouldPause() const;

#endif // THREADWORKER_H

When compiling, I am running into this error:

debug/threadworker.o: In function `ZN14QInterruptableD2Ev':
C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug/../qMyAwesomeApp/3rd-party/QThreading/QThreading/QInterruptable.h:9: undefined reference to `vtable for QInterruptable'
debug/threadworker.o: In function `ZN14QInterruptableC2Ev':
C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug/../qMyAwesomeApp/3rd-party/QThreading/QThreading/QInterruptable.h:4: undefined reference to `vtable for QInterruptable'
collect2.exe: error: ld returned 1 exit status
mingw32-make[1]: *** [Makefile.Debug:195: debug/MyAwesomeApp.exe] Error 1
mingw32-make: *** [Makefile:38: debug] Error 2
mingw32-make[1]: Leaving directory 'C:/Users/CybeX/QtProjects/build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug'
09:29:08: The process "F:\Qt\Qt5.13.1\Tools\mingw730_32\bin\mingw32-make.exe" exited with code 2.
Error while building/deploying project MyAwesomeApp (kit: Desktop Qt 5.13.1 MinGW 32-bit)
When executing step "Make"

I have look at solutions for implementing C++ interfaces and solutions for undefined references to destructors. I found this, and this, and this that reference my issue in particular.

As you can see, I have tried defining the destructor with

virtual ~QInterruptable(){

}

which results in the error above.

If I use a pure virtual desctructor like this:

virtual ~QInterruptable() = 0;

then I pass the problem on the the child class i.e. ThreadWorker with the following error:

debug/threadworker.o: In function `ZN12ThreadWorkerC2EP7QObject':
C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug/../qMyAwesomeApp/3rd-party/QThreading/QThreading/threadworker.cpp:28: undefined reference to `QInterruptable::~QInterruptable()'
debug/threadworker.o: In function `ZN12ThreadWorkerC2ESt8functionIFvvEE':
C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug/../qMyAwesomeApp/3rd-party/QThreading/QThreading/threadworker.cpp:33: undefined reference to `QInterruptable::~QInterruptable()'
debug/threadworker.o: In function `ZN12ThreadWorkerD2Ev':
C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug/../qMyAwesomeApp/3rd-party/QThreading/QThreading/threadworker.cpp:37: undefined reference to `QInterruptable::~QInterruptable()'
debug/threadworker.o: In function `ZN14QInterruptableC2Ev':
C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug/../qMyAwesomeApp/3rd-party/QThreading/QThreading/QInterruptable.h:4: undefined reference to `vtable for QInterruptable'
collect2.exe: error: ld returned 1 exit status
mingw32-make[1]: *** [Makefile.Debug:195: debug/MyAwesomeApp.exe] Error 1
mingw32-make: *** [Makefile:38: debug] Error 2
mingw32-make[1]: Leaving directory 'C:/Users/CybeX/QtProjects/build-MyAwesomeApp-Desktop_Qt_5_13_1_MinGW_32_bit-Debug'
09:33:51: The process "F:\Qt\Qt5.13.1\Tools\mingw730_32\bin\mingw32-make.exe" exited with code 2.
Error while building/deploying project MyAwesomeApp (kit: Desktop Qt 5.13.1 MinGW 32-bit)
When executing step "Make"

where the offending ThreadWorker.cpp lines are:

[28] ThreadWorker::ThreadWorker(QObject *parent) : QObject(parent)
[29] {
[30]     waitCondition = new QWaitCondition;
[31] }
[32] 
[33] ThreadWorker::ThreadWorker(std::function<void ()> func): runnable(func) {
[34]     waitCondition = new QWaitCondition;
[35] }
[36] 
[37] ThreadWorker::~ThreadWorker()
[38] {
[39]     if(waitCondition != nullptr){
[40]         delete waitCondition;
[41]     }
[42] }

How can I resolve this undefined reference to the interface destructor issue?

CybeX
  • 2,060
  • 3
  • 48
  • 115
  • Did you run qmake? – vahancho Oct 14 '19 at 07:44
  • incase someone may be wondering if it is a build issue, I clean and re-make before each build – CybeX Oct 14 '19 at 07:44
  • @vahancho yeah, was about to post it. I have it set on the IDE to call qmake each time, will do it again, for the hell of it – CybeX Oct 14 '19 at 07:44
  • if anyone is willing to take a look, find it at https://github.com/cybex-dev/QThreading – CybeX Oct 14 '19 at 07:49
  • My quick guess is that you should either make `pause` `resume` `interrupt` pure virtual (recommended) or provide some default definitions. Also in c++11 you can declare destructors (also virtual destructors) as default - this is the explicit way of telling compiler to generate it for you `virtual ~QInterruptable() = default;` – pptaszni Oct 14 '19 at 08:00
  • @Ptaq666 so it appears that making `pause` `resume` `interrupt` pure virtual and using the `default` destructor i.e. `virtual ~QInterruptable() = default;` did the trick. I have no idea why this works, specifically why the 'seemingly unrelated error' is resolved by these 2 changes. If you could post an answer with an explanation, I would be grateful – CybeX Oct 14 '19 at 08:24
  • Just for information, i have recompiled your project based on commit 675be82 on master branch with GCC 6.3.0 on Debian Stretch and no errors and no warnings. – Fryz Oct 14 '19 at 08:58
  • @Scab thanks for the info. I am using `mingw730_32` toolkit on Windows packaged with `Qt 5.13.1 x86` – CybeX Oct 14 '19 at 11:41

1 Answers1

2

You have the undefined references to vtable of your base class, because you did not provide definitions for all virtual (bot not pure-virtual) methods of your base class, that is: pause, resume, interrupt. Now if you declare that 3 methods to be pure virtual, no definitions for them are needed. Alternatively you could keep them as non-pure virtual and write some default definitions. Note that your destructor is also a virtual method and must be defined as well, however you can simplify it by explicitly telling the compiler to generate one for you virtual ~QInterruptable() = default. There is an entry in GCC FAQ about it.

pptaszni
  • 5,591
  • 5
  • 27
  • 43