Qt: Сигналы и слоты Ошибка: неопределенная ссылка на `vtable для

Следующий пример из этой ссылки: http://developer.kde.org/documentation/books/kde-2.0-development/ch03lev1sec3.html

#include <QObject>
#include <QPushButton>
#include <iostream>
using namespace std;

class MyWindow : public QWidget
{
    Q_OBJECT  // Enable slots and signals
    public:
        MyWindow();
    private slots:
        void slotButton1();
        void slotButton2();
        void slotButtons();
    private:
        QPushButton *button1;
        QPushButton *button2;
};

MyWindow :: MyWindow() : QWidget()
{
    // Create button1 and connect button1->clicked() to this->slotButton1()
    button1 = new QPushButton("Button1", this);
    button1->setGeometry(10,10,100,40);
    button1->show();
    connect(button1, SIGNAL(clicked()), this, SLOT(slotButton1()));

    // Create button2 and connect button2->clicked() to this->slotButton2()
    button2 = new QPushButton("Button2", this);
    button2->setGeometry(110,10,100,40);
    button2->show();
    connect(button2, SIGNAL(clicked()), this, SLOT(slotButton2()));

    // When any button is clicked, call this->slotButtons()
    connect(button1, SIGNAL(clicked()), this, SLOT(slotButtons()));
    connect(button2, SIGNAL(clicked()), this, SLOT(slotButtons()));
}

// This slot is called when button1 is clicked.
void MyWindow::slotButton1()
{
    cout << "Button1 was clicked" << endl;
}

// This slot is called when button2 is clicked
void MyWindow::slotButton2()
{
    cout << "Button2 was clicked" << endl;
}

// This slot is called when any of the buttons were clicked
void MyWindow::slotButtons()
{
    cout << "A button was clicked" << endl;
}

int main ()
{
    MyWindow a;
}

приводит к:

    [13:14:34 Mon May 02] ~/junkPrograms/src/nonsense  $make
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/opt/qtsdk-2010.05/qt/mkspecs/linux-g++-64 -I. -I/opt/qtsdk-2010.05/qt/include/QtCore -I/opt/qtsdk-2010.05/qt/include/QtGui -I/opt/qtsdk-2010.05/qt/include -I. -I. -o signalsSlots.o signalsSlots.cpp
g++ -m64 -Wl,-O1 -Wl,-rpath,/opt/qtsdk-2010.05/qt/lib -o nonsense signalsSlots.o    -L/opt/qtsdk-2010.05/qt/lib -lQtGui -L/opt/qtsdk-2010.05/qt/lib -L/usr/X11R6/lib64 -lQtCore -lpthread
signalsSlots.o: In function `MyWindow::MyWindow()':
signalsSlots.cpp:(.text+0x1a2): undefined reference to `vtable for MyWindow'
signalsSlots.cpp:(.text+0x1aa): undefined reference to `vtable for MyWindow'
signalsSlots.o: In function `MyWindow::MyWindow()':
signalsSlots.cpp:(.text+0x3e2): undefined reference to `vtable for MyWindow'
signalsSlots.cpp:(.text+0x3ea): undefined reference to `vtable for MyWindow'
signalsSlots.o: In function `main':
signalsSlots.cpp:(.text+0x614): undefined reference to `vtable for MyWindow'
signalsSlots.o:signalsSlots.cpp:(.text+0x61d): more undefined references to `vtable for MyWindow' follow
collect2: ld returned 1 exit status
make: *** [nonsense] Error 1

vtable для виртуальных функций, AFAIK, в чем причина ошибки?


person Aquarius_Girl    schedule 02.05.2011    source источник
comment
Я не понимаю, в чем проблема, но хочу отметить, что учебник, который вы используете, довольно устарел. Я предлагаю вам посмотреть руководства в документации Qt 4.7.   -  person ypnos    schedule 02.05.2011
comment
@ypnos, спасибо, но тут на 4.7 нет работающего примера, который я мог бы просто вставить и запустить :(   -  person Aquarius_Girl    schedule 02.05.2011
comment
Возможный дубликат Qt moc с реализациями внутри файлов заголовков?   -  person Stefan Monov    schedule 05.01.2017
comment
Возможный дубликат Неопределенной ссылки на vtable. Попытка скомпилировать проект Qt   -  person iammilind    schedule 14.06.2017


Ответы (5)


Похоже, что moc не генерирует код для вашего QObject, потому что вы объявляете его в .cpp файле. Самый простой способ исправить это - переместить объявление MyWindow в заголовок и добавить заголовок в список HEADERS в файле .pro:

HEADERS += yourheader.h 

Затем перезапустите qmake.

(Обратите внимание, что книга KDE 2.0, которую вы просматриваете, сильно устарела)

person Frank Osterfeld    schedule 02.05.2011
comment
Спасибо за ответ, но нет ли способа сохранить объявление и определение в файле .cpp? - person Aquarius_Girl; 02.05.2011
comment
Попробуйте использовать HEADERS + = your.cpp. Обычно, хотя это возможно, я нахожу объявления QObject настолько болезненными, что предпочитаю использовать их (частные) заголовки. Что отлично работает со всеми системами сборки, будь то qmake, cmake, ... - person Frank Osterfeld; 02.05.2011
comment
Еще раз спасибо, я разделил .h, .cpp и main: mad: и это устранило ошибку, я еще не изучил детали, касающиеся файла moc. - person Aquarius_Girl; 02.05.2011
comment
Каждый раз, когда вы объявляете объект QObject внутри файла filename.cpp, вы должны добавить #include "filename.moc" в конец вашего файла .cpp, и qmake сделает за вас правильные действия. Например, это обычная практика в KDE. - person andref; 02.05.2011
comment
Отличный ответ. Раздражает то, что Qt накладывает дополнительные ограничения по сравнению с самим C ++, но я думаю, я могу с этим смириться. - person paxdiablo; 01.08.2016

Может быть, слишком поздно, но ... У меня была такая же проблема, и я долго боролся, чтобы найти, откуда она взялась.

Щелкните правой кнопкой мыши свой проект и выберите «Запустить qmake» для новой сборки классов MOC. Обычно он запускается автоматически ...

Компилятор moc генерирует заглушки и вызовы в moc_xxxx.cpp и генерирует материал vtable

person sylvain    schedule 29.12.2012
comment
Я не использую qtcreator. Я запускал qmake много раз, прежде чем спрашивать здесь. Это не помогло. - person Aquarius_Girl; 30.12.2012
comment
@AnishaKaul Точно так же. Запуск qmake для меня ничего не исправляет. Если я запустил qmake --project, он регенерирует .pro, и я смогу скомпилировать, но это объединит все изменения, которые люди внесли в .pro, что действительно плохо. - person Freedom_Ben; 03.05.2013
comment
1 ++ это исправит мою проблему - person Ivan; 26.09.2013
comment
исправил и мою проблему !! Спасибо +1 - person normalUser; 11.02.2015
comment
После добавления Q_OBJECT в файл .h и запуска qmake он сработал +1 - person ffttyy; 23.02.2017

Просто измените свой Main () следующим образом:

#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWindow w;

    w.show();

    return a.exec();
}
person anj    schedule 02.05.2011

На основе комментария andref чуть выше, когда все находится в одном файле cpp, таком как stuff.cpp, вам нужно добавить в конец файла:

#include "moc_stuff.cpp"

(это с Qt 4.7.0)

person calandoa    schedule 04.06.2012
comment
Используя Qt 4.8, у меня это не сработало. Я должен был сделать то, что предлагает упомянутый комментарий. - person tshepang; 24.10.2012

Эта проблема может быть вызвана некоторыми из следующих причин. Время от времени я натыкался на них всех.


В заголовке вашего класса может отсутствовать макрос Q_OBJECT. Добавьте макрос в заголовок, как уже отмечалось в других ответах.

class MyWidg : public QWidget
{
    Q_OBJECT

Заголовок вашего класса не может быть проанализирован moc. Добавьте файл заголовка в определения HEADERS файла проекта .pro (или .pri).

HEADERS += file.h

Если ничего из вышеперечисленного не соответствует действительности, вам, вероятно, нужно снова запустить qmake, чтобы убедиться, что moc снова анализирует заголовок, на всякий случай, если макрос Q_OBJECT был добавлен в заголовок после запуска qmake. Просто запустите qmake еще раз.

person kotsos    schedule 06.03.2018