Virtual functions causing link errors

Patrik Gwét patrikgwet at gmail.com
Mon Dec 8 07:30:09 GMT 2014


I am struggling with an issue while I am using external .h files in my
project.

I am using Qt5 with MSVC2012. In my main file, I am including a header
file from a KDE application. I put some INCLUDEPATH in the .pro file
to link correctly.

The piece of code I am in trouble with is the following:

main.cpp
> ...
> #include <Doc.h>
>
> int main(int argc, char *argv[])
> ...
>

The Doc.h belongs to the KDE application source code. Including that
file includes many other files in several directories in the KDE
application source code.

Currently, the KUndo2Stack.h and the KUndo2Stack.cpp files are the
files I am struggling with since three days now.

When I run QMake and compile, I get a link 2001 errors due to
unresolved externals with virtual functions in the KUndo2QStack class
defined and implemented in those files. Here is an extract:

#ifndef QT_NO_UNDOSTACK
>
> class KUNDO2_EXPORT KUndo2QStack : public QObject
> {
>     Q_OBJECT
> //    Q_DECLARE_PRIVATE(

KUndo2QStack)
    Q_PROPERTY(bool active READ isActive WRITE setActive)
    Q_PROPERTY(int undoLimit READ undoLimit WRITE setUndoLimit)

public:
    explicit KUndo2QStack(QObject *parent = 0);
    virtual ~KUndo2QStack();
    void clear();

    void push(KUndo2Command *cmd);

    bool canUndo() const;
    bool canRedo() const;
    QString undoText() const;
    QString redoText() const;

    int count() const;
    int index() const;
    QString actionText(int idx) const;
    QString text(int idx) const;

#ifndef QT_NO_ACTION
    QAction *createUndoAction(QObject *parent) const;
    QAction *createRedoAction(QObject *parent) const;
#endif // QT_NO_ACTION

    bool isActive() const;
    bool isClean() const;
    int cleanIndex() const;

    void beginMacro(const QString &text);
    void endMacro();

    void setUndoLimit(int limit);
    int undoLimit() const;

    const KUndo2Command *command(int index) const;

public Q_SLOTS:
    void setClean();
    virtual void setIndex(int idx);
    virtual void undo();
    virtual void redo();
    void setActive(bool active = true);

Q_SIGNALS:
    void indexChanged(int idx);
    void cleanChanged(bool clean);
    void canUndoChanged(bool canUndo);
    void canRedoChanged(bool canRedo);
    void undoTextChanged(const QString &undoActionText);
    void redoTextChanged(const QString &redoActionText);

private:
    // from QUndoStackPrivate
    QList<KUndo2Command*> m_command_list;
    QList<KUndo2Command*> m_macro_stack;
    int m_index;
    int m_clean_index;
    KUndo2Group *m_group;
    int m_undo_limit;

    // also from QUndoStackPrivate
    void setIndex(int idx, bool clean);
    bool checkUndoLimit();

    Q_DISABLE_COPY(KUndo2QStack)
    friend class KUndo2Group;
};

class KUNDO2_EXPORT KUndo2Stack : public KUndo2QStack
{
public:
    explicit KUndo2Stack(QObject *parent = 0);

    // functions from KUndoStack
    QAction* createRedoAction(KActionCollection* actionCollection,
const QString& actionName = QString());
    QAction* createUndoAction(KActionCollection* actionCollection,
const QString& actionName = QString());
};

#endif // QT_NO_UNDOSTACK

Note that the unresolved links occur only for virtual functions. Those
functions are implemented as it follows:

KUndo2QStack::~KUndo2QStack()
{
#ifndef QT_NO_UNDOGROUP
    if (m_group != 0)
        m_group->removeStack(this);
#endif
    clear();
}

void KUndo2QStack::undo()
{
    if (m_index == 0)
        return;

    if (!m_macro_stack.isEmpty()) {
        qWarning("KUndo2QStack::undo(): cannot undo in the middle of a
macro");
        return;
    }

    int idx = m_index - 1;
    m_command_list.at(idx)->undo();
    setIndex(idx, false);
}

void KUndo2QStack::redo()
{
    if (m_index == m_command_list.size())
        return;

    if (!m_macro_stack.isEmpty()) {
        qWarning("KUndo2QStack::redo(): cannot redo in the middle of a
macro");
        return;
    }

    m_command_list.at(m_index)->redo();
    setIndex(m_index + 1, false);
}

void KUndo2QStack::setIndex(int idx)
{
    if (!m_macro_stack.isEmpty()) {
        qWarning("KUndo2QStack::setIndex(): cannot set index in the
middle of a macro");
        return;
    }

    if (idx < 0)
        idx = 0;
    else if (idx > m_command_list.size())
        idx = m_command_list.size();

    int i = m_index;
    while (i < idx)
        m_command_list.at(i++)->redo();
    while (i > idx)
        m_command_list.at(--i)->undo();

    setIndex(idx, false);
}


I have turned this question upside down looking for answers on the web
and the only time I got something was when I deleted the word virtual
off all the related functions. It cancelled the errors but I got an
unresolved link2019 error with the destructor of the class KUndo2Stack
(see the code above). The destructor I am talking about is the default
one, you won't see any definition or implementation of it.

I need some help to understand what is really going on and how to fix it.

The exact error messages are:

main.obj:-1: error: LNK2001: unresolved external symbol "public:
> virtual struct QMetaObject const * __cdecl
> KUndo2QStack::metaObject(void)const "
> (?metaObject at KUndo2QStack@@UEBAPEBUQMetaObject@@XZ)
>
> main.obj:-1: error: LNK2001: unresolved external symbol "public:
> virtual void * __cdecl KUndo2QStack::qt_metacast(char const *)"
> (?qt_metacast at KUndo2QStack@@UEAAPEAXPEBD at Z)
>
> main.obj:-1: error: LNK2001: unresolved external symbol "public:
> virtual int __cdecl KUndo2QStack::qt_metacall(enum
> QMetaObject::Call,int,void * *)"
> (?qt_metacall at KUndo2QStack@@UEAAHW4Call at QMetaObject@@HPEAPEAX at Z)
>
> main.obj:-1: error: LNK2001: unresolved external symbol "public:
> virtual void __cdecl KUndo2QStack::setIndex(int)"
> (?setIndex at KUndo2QStack@@UEAAXH at Z)
>
> main.obj:-1: error: LNK2001: unresolved external symbol "public:
> virtual void __cdecl KUndo2QStack::undo(void)"
> (?undo at KUndo2QStack@@UEAAXXZ)
>
> main.obj:-1: error: LNK2001: unresolved external symbol "public:
> virtual void __cdecl KUndo2QStack::redo(void)"
> (?redo at KUndo2QStack@@UEAAXXZ)
>
> main.obj:-1: error: LNK2019: unresolved external symbol
> "__declspec(dllimport) public: virtual __cdecl
> KUndo2Stack::~KUndo2Stack(void)" (__imp_??1KUndo2Stack@@UEAA at XZ)
> referenced in function "public: virtual void * __cdecl
> KUndo2Stack::`scalar deleting destructor'(unsigned int)"
> (??_GKUndo2Stack@@UEAAPEAXI at Z)
>
> debug\whitehall_0_2.exe:-1: error: LNK1120: 7 unresolved externals


*Patrik GWET *
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/calligra-devel/attachments/20141208/20df8379/attachment.htm>


More information about the calligra-devel mailing list