Подтвердить что ты не робот

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 вместо этого не исправлять вещи.
4b9b3361

Ответ 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.