Q_OBJECT throwing 'undefined ссылка на ошибку vtable'
Я использую Qt Creator 2.0.1 с Qt 4.7.0 (32 бит) в Windows 7 Ultimate 32 бит.
Рассмотрим следующий код, который является минимальным для возникновения ошибки:
class T : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
T() {}
QRectF boundingRect() const {return QRectF();}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget) {}
};
int main()
{
T t;
return 0;
}
Вышеупомянутый фрагмент кода вызывает следующие ошибки компоновщика:
В функции `T ':
undefined ссылка на `vtable для T '
undefined ссылка на `vtable для T '
В функции `~ T ':
undefined ссылка на `vtable для T '
undefined ссылка на `vtable для T '
Если я прокомментирую строку, содержащую Q_OBJECT
, она компилируется отлично. Мне нужен сигнал и слоты с QGraphicsItem
, поэтому мне нужно Q_OBJECT
.
Что не так с кодом? Спасибо.
Ответы
Ответ 1
Это потому, что единица, сгенерированная MOC, не включена в процесс связывания. Или, может быть, он вообще не сгенерирован. Первое, что я хотел бы сделать, это поместить объявление класса в отдельный заголовочный файл, возможно, система сборки не сканирует файлы реализации.
Другая возможность заключается в том, что рассматриваемый класс некогда не принадлежал системе метаобъектов Qt (то есть он не имел Q_OBJECT или, возможно, вообще не наследовался от QObject), поэтому qmake нужно запустить снова в порядке для создания необходимых правил для MOC. Самый простой способ заставить qmake запускаться - внести незначительные изменения в файл проекта, чтобы обновить его временную метку, например добавление и удаление некоторого пробела. Или, если вы используете Qt Creator, просто выберите "Запустить qmake" из контекстного меню проекта.
Ответ 2
Если вы хотите определить подкласс QObject
в исходном файле, вам нужно добавить строку
#include "file.moc"
в какой-то момент после определения вашего класса, где имя исходного файла было file.cpp. Вам нужно будет повторно запустить qmake
, конечно, чтобы соответствующее правило запускать moc
добавилось в Makefile.
Только в том случае, если в файле заголовка присутствие Q_OBJECT
в определении класса вызывает moc
для вызова. Если это исходный файл, вам понадобится эта дополнительная строка, чтобы принудительно использовать moc
.
Я уверен, что аналогичный вопрос был задан раньше, но я не смог его найти.
Ответ 3
Вот рабочий код, добавленный со всеми исправлениями, содержащимися в других вопросах (исправлена чистая компиляция и эти исправления):
#include <QGraphicsItem>
class T : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem) //Required.
public:
T() {}
QRectF boundingRect() const {return QRectF();}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget) {}
};
int main(int argc, char *argv[])
{
T *t = new T;
return 0;
}
#include "main.moc" // Required.
Итак, настоящий кредит Troubadour и serge_gubenko
Ответ 4
Поместите классы Q_OBJECT в отдельные файлы. Это один .h и один .cpp для каждого класса. В этом отношении макросы метатега Qt выглядят отвратительными.
Кроме того, вы можете использовать QGraphicsObject для своей цели. Экономит вас некоторое время там.
Изменить: Я вижу, что вы используете Creator. Используйте новую функцию класса С++ в New File или Project, чтобы создать файл "правильным способом":)
Ответ 5
есть несколько вещей, на которые нужно смотреть:
- Добавить QT + = gui в свой файл pro
- Убедитесь, что вы определяете классы, полученные из QObject, только в ваших файлах заголовков (отредактируйте: как указано в Troubadour, это не требуется).
- Добавить Q_INTERFACES (QGraphicsItem) в объявление вашего класса T
Ниже приведен пример :
t.h:
class T : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
T();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};
t.cpp:
T::T() {}
QRectF T::boundingRect() const
{
return QRectF();
}
void T::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
Я пробовал компилировать код выше и не имел проблем с ним.
надеюсь, что это поможет, считает