PDA

View Full Version : QOBJECT and undefined reference to vtable errors



stargazer
11th January 2011, 17:53
I've been working on a plugin to an third party application an have recently introduced a GUI dialogue module into the project. The problem is that I can't get around an error I am getting which is:

undefined reference to 'vtable for StelModule'

I have reduced my code down to the basics and have discovered that when I remove Q_OBJECT from the class definition within the hpp file the everything compiles Ok. Obviously because this is a GUI it will require Q_OBJECT.

I've found a few posts on the subject via Google and it would appear that this is something to do with .moc files. Unfortunately things start to get rather confusing after that, but as far as I understand, QT 4.7.1 (2010.05) should manage this pretty much authormatically. I have seen references to including a .moc file in the .cpp file but there seem to be no .moc files being generated. Insetad I do see a moc_mymodule.cpp and moc_mymodule.o in the debug directory. I'm also confused about what, if anything, should be added to the makefile and the qmake.conf file?

Here is my code:


HPP file:


#ifndef GPSLOCATOR_HPP
#define GPSLOCATOR_HPP

#include "StelGui.hpp"
#include "StelModule.hpp"
#include "StelFader.hpp"
#include "StelPluginInterface.hpp"

class QTimer;
class QPixmap;
class StelButton;
class GpsLocatorDialog;


//! Dynamically loaded plug-in

class GpsLocator : public StelModule
{
Q_OBJECT
public:
GpsLocator();
virtual ~GpsLocator();

};

/* COMMENTED OUT FOR TESTING
virtual ~GpsLocator();
// Methods defined in StelModule class
virtual void init();
virtual void update(double deltaTime);
virtual void draw(StelCore* core);
virtual double getCallOrder(StelModuleActionName actionName) const;
signals:

public slots:
// void enableGpsLocator(bool b);

private:
//Toolbar button
QPixmap* pixmapHover;
QPixmap* pixmapOnIcon;
QPixmap* pixmapOffIcon;
StelButton* toolbarButton;

// Dialog Window
GpsLocatorDialog* dialogWindow;

};
*/

//! This class is used by Qt to manage a plug-in interface
class GpsLocatorStelPluginInterface : public QObject, public StelPluginInterface
{
Q_OBJECT
Q_INTERFACES(StelPluginInterface)
public:
virtual StelModule* getStelModule() const;
virtual StelPluginInfo getPluginInfo() const;
};

#endif // GPSLOCATOR_HPP



CPP file:



#include "gpslocator.hpp"

#include "StelApp.hpp"
#include "StelCore.hpp"
#include "StelFileMgr.hpp"
#include "StelGui.hpp"
#include "StelGuiItems.hpp"
#include "StelLocaleMgr.hpp"
#include "StelModuleMgr.hpp"
#include "StelPainter.hpp"

#include <QAction>
#include <QDebug>
#include <QPixmap>
#include <QString>


//! This method is the one called automatically by the StelModuleMgr
//! just after loading the dynamic library
StelModule* GpsLocatorStelPluginInterface::getStelModule() const
{
// return new GpsLocator();
return false;
}

StelPluginInfo GpsLocatorStelPluginInterface::getPluginInfo() const
{
// Allow to load the resources when used as a static plugin
// Q_INIT_RESOURCE(gpsLocatorRsc);

StelPluginInfo info;
info.id = "GpsLocator";
info.displayedName = "GPS Locator Plugin";
info.authors = "Jan Chajecki";
info.contact = "http://stellarium.org/";
info.description = "Allows Stellarium co-ordinates to be updated from a GPS device";
return info;
}

Q_EXPORT_PLUGIN2(GpsLocator, GpsLocatorStelPluginInterface)


//! Constructor
GpsLocator::GpsLocator()
{
// setObjectName("GpsLocator");
}

//! Destructor
GpsLocator::~GpsLocator()
{
}

Can anyone clearify what I need to do to get rid of this error please?

vpicaver
11th January 2011, 18:28
Usually when this happens you need to re-run qmake and make sure you've implemented all the slots for your class.

high_flyer
11th January 2011, 20:49
undefined reference to 'vtable for StelModule'
Where is StelModule defined, and where implemented?
Can we see the code for that?
Does StelModule derive from QObject - does is call Q_OBJECT macro?

stargazer
12th January 2011, 10:44
Is it OK to post someone else's code?

high_flyer, the StelModule class is defined in StelModule.hpp. This is not one of my classes but part of an open source project that is licencsed under GNU. Since its accessible to all anyway so I'm sure there should be not problem in at least providing this snippet of the class definition:



class StelModule : public QObject
{
// Do not add Q_OBJECT here!!
// This make this class compiled by the Qt moc compiler and for some unknown reasons makes it impossible to dynamically
// load plugins on windows.
public:
StelModule() {;}

virtual ~StelModule() {;}

//! Initialize itself.
//! If the initialization takes significant time, the progress should be displayed on the loading bar.
virtual void init() = 0;

//! Called before the module will be delete, and before the openGL context is suppressed.
//! Deinitialize all openGL texture in this method.
virtual void deinit() {;}
etc...


It appears to be derived from the QObject class but it does not have the Q_OBJECT macro. I would point out though that the code for other plugins to this project, including the provided examples, have a Q_OBJECT macro in their class definition.

Also, the presence of the Q_OBJECT macro in the GpsLocatorStelPluginInterface class does not seem to generate an error. I tested this by commenting out the GpsLocator class and its corresponding implementation in the CPP file. The remaining code compiled without errors.

The comment after the class header is interesting and may be relevant, but I'm not sure what it means, except that evidently someone was having trouble with moc...

high_flyer
12th January 2011, 10:48
Code snippets, specially of a class decleration will not be of much interest to anyone.
At any rate, you can answer my last question, and check it in your code, with out posting any code.

stargazer
12th January 2011, 14:18
Ok, noted for future reference!

vpicaver, [I]'ve tried adding slots and signals but that made no difference.

According to the information in the QT reference documentation, the QT_OBJECT macro is mandatory, but slots and signals are not.


Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.


However this seems to indicate that I need to run the Meta Object Compiler, however the information I found in the linked page suggests seems to state that this is already done automatically:


We recommend using the qmake makefile generation tool for building your makefiles. This tool generates a makefile that does all the necessary moc handling.

Isn't qmake run every time you compile?

high_flyer
12th January 2011, 14:40
It appears to be derived from the QObject class but it does not have the Q_OBJECT macro. I would point out though that the code for other plugins to this project, including the provided examples, have a Q_OBJECT macro in their class definition.
Lets make some things clear:
the Q_OBJECT macro is only needed (and moc'ing), if you are using signals and slots.
If you are not using signal/slots, you don't have to use Q_OBJECT and you don't have to moc that class.
Therefore I would not put Q_OBJECT macro in the interface since this will force all implementing class to use it- which is not always what you want.

OnlyK
25th April 2011, 06:29
I also got this problem and don't know how to solve it.
I declare a prototype nested class in header file, declaration and definition in source file.


class Service::Private : public QObject {
Q_OBJECT

public:
Private(const QString &aCMName, const QString &aName) {}

QString mName;
QString mCMName;
Tp::ConnectionManagerPtr mCM;
QList<Service::ServiceParameter> mParameters;

public slots:
void onCMReady(Tp::PendingOperation *operation) {}
};

Added after 20 minutes:

I see this problem on Meta-object compiler document, at Limitations:

Nested Classes Cannot Have Signals or Slots
Here's an example of the offending construct:

class A
{
public:
class B
{
Q_OBJECT

public slots: // WRONG
void b();
};
};



I also got this problem and don't know how to solve it.
I declare a prototype nested class in header file, declaration and definition in source file.


class Service::Private : public QObject {
Q_OBJECT

public:
Private(const QString &aCMName, const QString &aName) {}

QString mName;
QString mCMName;
Tp::ConnectionManagerPtr mCM;
QList<Service::ServiceParameter> mParameters;

public slots:
void onCMReady(Tp::PendingOperation *operation) {}
};