PDA

View Full Version : Simple demo won't link - undef vtable and Q_OBJECT



DrunkenUFOPilot
14th January 2011, 21:14
This small demo (extracted from a less small demo) won't link. I've gone over everything and am puzzled. I hope it's a simple goof, but not something too obvious (for if it _is_ obvious, that doesn't say much for my IQ today.) I'm semi-experienced with Qt4, but work entirely on an existing huge app, rarely creating new ones - until today. Now I'm trying to write a quick demo of something. But this linking problem is a brick wall to any progress.

The line with Q_OBJECT is shown commented out - this compiles and links fine, but the slot printmyplot() is never invoked when the "print" button is clicked.

Uncommenting the Q_OBJECT line causes the linker to complain "undefined reference to `vtable for MyMainWindow'" (four times!) and no executable is produced.

Naturally I googled this error message, and found the most common problems were 1) failing to re-run qmake (but I have run it repeatedly, including qmake -project to be really sure); 2) some method is declared in a class but not defined (but I have defs for all my methods, all two of them); 3) classes don't override an abstract method inherited from a base class (QWidget doesn't have any, AFIK). Note that I've got all the source in one file, badslot.cpp, so the problem isn't header files not listed in .pro or the Makefile.

What's the problem with this source?

Contents of badslot.cpp:


// uncomment the Q_OBJECT:
// get undefined reference to `vtable for MyMainWindow'
//
// commented out: it compiles, but printmyplot() isn't called.
//

#include <QtGui>
#include <QWidget>
#include <stdio.h>
#include <unistd.h>


class MyMainWindow : public QWidget
{
// Q_OBJECT /*uncomment this to get linker error */

public:
MyMainWindow(QWidget *parent=0);
~MyMainWindow();

void createcontent();

public slots:
void printmyplot();

private:
QPushButton *print_button;
QPushButton *quit_button;
};

MyMainWindow::~MyMainWindow() {}

MyMainWindow::MyMainWindow(QWidget *parent)
: QWidget(parent),
print_button(0),
quit_button(0)
{
resize(500,500);
setWindowTitle("QWT Simple Demo #1");
}


void MyMainWindow::createcontent()
{
print_button = new QPushButton("print", this);
quit_button = new QPushButton("quit", this);

QHBoxLayout *bottomrow = new QHBoxLayout;
bottomrow->addWidget(print_button);
bottomrow->addWidget(quit_button);
setLayout(bottomrow);

connect(quit_button, SIGNAL(clicked()),
this, SLOT(close()));
connect(print_button, SIGNAL(clicked()),
this, SLOT(printmyplot()));

}


void MyMainWindow::printmyplot()
{
printf("entered printmyplot \n");
setWindowTitle("printing...");
sleep(2);
setWindowTitle("(normal title goes here)");
prntf("returning from printmyplot \n");
}


int main(int nargs, char** args)
{
QApplication app(nargs, args);
MyMainWindow *mainwindow = new MyMainWindow;
mainwindow->createcontent();
mainwindow->show();
return app.exec();
}


The .pro file, created by qmake -project with debug manually added in, contains:


TEMPLATE = app
TARGET = badslot
CONFIG += qt debug

DEPENDPATH += .
INCLUDEPATH += .
# Input
SOURCES += badslot.cpp

Zlatomir
14th January 2011, 21:56
First "solution" i don't really recommend this
is to add the following line in the badslot.cpp file:

#include "badslot.moc"
then from Build menu Run qmake then Rebuild

But the good solution is to always have classes (even if they are not using QOBJECT macro) declared in a CLASSNAME.h and defined in CLASSNAME.cpp, then you don't need to manually include the .moc file

poporacer
14th January 2011, 22:06
You didn't declare your signals or one of your slots. You have to declare your signals and slots.
you need something like:

signals:
void quit_button_clicked();
void print_button_clicked();

public slots:
void printmyplot();
void quit_button_clicked();

DrunkenUFOPilot
14th January 2011, 23:57
Aha! You are right. I broke up my one source file into four, having now .hpp and .cpp. After running qmake -project, it works.

I guess I shouldn't put "Qt guru" on my resume just yet...