Qt Linker Error: "undefined ссылка на vtable"
Это мой заголовок:
#ifndef BARELYSOCKET_H
#define BARELYSOCKET_H
#include <QObject>
//! The First Draw of the BarelySocket!
class BarelySocket: public QObject
{
Q_OBJECT
public:
BarelySocket();
public slots:
void sendMessage(Message aMessage);
signals:
void reciveMessage(Message aMessage);
private:
// QVector<Message> reciveMessages;
};
#endif // BARELYSOCKET_H
Это мой класс:
#include <QTGui>
#include <QObject>
#include "type.h"
#include "client.h"
#include "server.h"
#include "barelysocket.h"
BarelySocket::BarelySocket()
{
//this->reciveMessages.clear();
qDebug("BarelySocket::BarelySocket()");
}
void BarelySocket::sendMessage(Message aMessage)
{
}
void BarelySocket::reciveMessage(Message aMessage)
{
}
Я получаю ошибку Linker:
undefined reference to 'vtable for BarelySocket'
- Это означает, что у меня виртуальный метод не реализован. Но есть
не являются виртуальными методами в моем классе.
- Я прокомментировал векторное мышление о том, что это была причина, но
ошибка не исчезла.
-
Message
является сложным struct
, но даже с использованием int
вместо этого
не исправлять вещи.
Ответы
Ответ 1
Каждый раз, когда вы добавляете новый вызов макроса Q_OBJECT, вам нужно снова запустить qmake. Проблема vtables, о которой вы говорите, напрямую связана с этим.
Просто запустите qmake, и вам должно быть хорошо, если у вас нет других проблем в вашем коде.
Ответ 2
Я видел много способов решить проблему, но не объяснил, почему это происходит, поэтому здесь идет.
Когда компилятор видит класс с виртуальными функциями (прямо объявлен или унаследован), он должен создать vtable для этого класса. Поскольку классы обычно определяются в заголовках (и, следовательно, появляются в нескольких единицах перевода), вопрос заключается в том, где разместить vtable.
В общем случае проблему можно решить, создав vtable в каждом TU, где определен класс, а затем пусть компоновщик устранит дубликаты. Поскольку определения классов должны быть одинаковыми в каждом случае ODR, это безопасно. Однако он также замедляет компиляцию, разбивает объектные файлы и требует, чтобы компоновщик выполнял больше работы.
Таким образом, в качестве оптимизации компиляторы будут, когда это возможно, выбирать конкретный TU для ввода vtable. В общем С++ ABI этот TU является тем, где реализована ключевая функция класса, где ключ function - первая виртуальная функция-член, объявленная в классе, но не определенная.
В случае классов Qt они обычно начинаются с макроса Q_OBJECT, и этот макрос содержит декларацию
virtual const QMetaObject *metaObject() const;
который, поскольку он является первой виртуальной функцией в макросе, обычно будет первой виртуальной функцией класса и, следовательно, ее ключевой функцией. Поэтому компилятор не будет выпускать vtable в большинстве TU, только тот, который реализует metaObject
. И эта реализация функции автоматически записывается moc
при обработке заголовка. Таким образом, вам нужно moc
обработать ваш заголовок, чтобы сгенерировать новый .cpp файл, а затем включить файл .cpp в вашу компиляцию.
Итак, если у вас есть новый заголовок, который определяет класс QObject
-derived, вам нужно перезапустить qmake
, чтобы он обновлял ваши make файлы для запуска moc
в новом заголовке и скомпилировал полученный .cpp файл.
Ответ 3
Я столкнулся с этой ошибкой после того, как создал небольшой класс внутри небольшого файла main.cpp, который я создал для тестирования.
После futzing в течение часа или около того, я, наконец, переместил этот класс из main.cpp и в автономный файл hpp, обновил файл .pro(project), а проект был построен отлично. Возможно, это не было проблемой, но я полагал, что это будет полезной информацией.
Ответ 4
Из опыта: часто qmake && сделать чистым && make помогает.
Я лично понимаю, что иногда эффекты открытия/кэширования изменений/независимо от того, что я не знаю, ххххх. Я не могу сказать, почему, но это первое, что я делаю, когда сталкиваюсь с такой ошибкой.
кстати. там опечатка at > recive <
Вы забыли вызвать конструктор QObject в своем конструкторе (в списке инициализаторов). (Это не устраняет ошибку, хотя)
Ответ 5
Для меня я заметил из журналов сборки, что moc не был вызван. Чистое все не помогло. Поэтому я удалил .pro.user, перезапустил IDE и сделал трюк.
Ответ 6
Сигналы не должны иметь реализацию (это будет порождено Qt). Удалите реализацию reciveMessage
из вашего .cpp файла. Это может решить вашу проблему.
Еще одна вещь, которую я видел: поскольку класс BarelySocket
наследуется от QObject, он должен иметь виртуальный деструктор, чтобы избежать проблемы во время уничтожения. Это должно быть сделано для всех классов, которые наследуются от другого класса.
Ответ 7
Когда вы получаете класс из QOBject (и используете макрос Q_OBJECT), не забудьте специально определить и создать классы конструктора и деструктора. Недостаточно использовать конструктор/деструкторы по умолчанию для компилятора. Совет по очистке/запуску qmake (и очистка ваших файлов moc_) по-прежнему применяется.
Это устранило мою аналогичную проблему.
Ответ 8
Я боролся с этим часом ошибок. Решила его, поместив файлы .cpp и .h в отдельную папку (!!).
Затем добавлена папка в файле .pro:
INCLUDEPATH + = $$ {_ PRO_FILE_PWD _}/../MyClasses/CMyClassWidget
а затем добавил файлы .cpp и .h.
Работает наконец.
Ответ 9
Я нашел еще одну причину, почему вы можете это увидеть - поскольку qmake
анализирует ваши файлы классов, если вы внесли изменения нестандартным способом, вы можете получить эту ошибку. В моем случае у меня был специальный диалог, который унаследовал от QDialog, но я только хотел, чтобы это компилировать и запускать при создании для Linux, а не в Windows или OSX. Я просто #ifdef __linux__
класс, поэтому он не компилировался, но в Linux, хотя был определен __linux__
, он отбрасывал qmake
.