2010-03-31 14 views
51

Questo è il mio colpo di testa: Qt Linker di errore: "undefined reference to 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 

Questa è la mia classe:

#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) 
{ 
} 

ottengo un errore Linker:

undefined reference to 'vtable for BarelySocket' 
  • Ciò implica che ho un metodo virtuale non implementato. Ma lo non sono metodi virtuali nella mia classe.
  • Ho commentato il vettore pensando che fosse la causa, ma l'errore non è andato via.
  • Il Message è un complesso struct, ma utilizzando anche int invece ha risolto .
+7

Hai provato una build pulita iniziando dall'esecuzione di 'qmake'? Questo può accadere se 'moc' non elabora l'intestazione della tua classe per qualche motivo. –

+0

Sto lavorando con QT Creator. Ho copiato tutti i file cpp in un nuovo Projekt pulito. Ho eliminato l'implementazione dello slot che ho codificato in fault. Rispetto ai problemi se n'è andato. Grazie per il vostro aiuto! – Thomas

risposta

10

Per esperienza: spesso un qmake & & make clean & & make aiuta. Personalmente percepisco che a volte il cambiamento scoperta/effetti di memorizzazione nella cache/qualsiasi cosa-non-so-xxxxx. Non posso dire perché, ma è la prima cosa che faccio quando incontro questo tipo di errore.

btw. c'è un refuso su> recive <

Hai dimenticato di chiamare il costruttore QObject nel tuo costruttore (nella lista di inizializzazione). (Tuttavia non risolve l'errore)

+5

Ciò è particolarmente utile quando il file è esistito ma non contiene alcun riferimento Q_OBJECT al suo interno quando qmake è stato eseguito.qmake quindi non crede che sia necessario eseguire moc e si finisce con errori vtable. Il make clean non è sempre necessario, ma è quando vengono apportate alcune modifiche strutturali. –

+4

Assicurati inoltre che barelysocket.h si trovi nella sezione HEADERS del tuo file pro. – chalup

2

I segnali non devono avere un'implementazione (Questo sarà generato da Qt). Rimuovi l'implementazione reciveMessage dal tuo file .cpp. Questo potrebbe risolvere il tuo problema.

Un'altra cosa che ho visto: poiché la classe BarelySocket eredita da QObject, deve avere un distruttore virtuale per evitare problemi durante la distruzione. Questo deve essere fatto per tutte le classi che ereditano da un'altra classe.

+0

La rimozione di receiveMessage è necessaria, ma dovrebbe piuttosto causare l'errore "simbolo definito in più". Se la classe base (QObject in questo caso) ha un distruttore virtuale, i distruttori in tutte le classi derivate sono automaticamente virtuali. Quindi non è un problema qui. – chalup

12

Mi sono imbattuto in questo errore dopo aver creato una piccola classe all'interno di un piccolo file "main.cpp" che avevo creato per testare qualcosa.

Dopo aver trascorso un'ora o giù di lì, ho finalmente spostato quella classe da main.cpp e in un file hpp standalone, aggiornato il file .pro (progetto) e il progetto è stato quindi realizzato perfettamente. Questo potrebbe non essere stato il problema qui, ma ho pensato che sarebbe comunque utile.

+0

Ho fatto esattamente lo stesso errore oggi! Perso circa un'ora circa ... –

109

Ogni volta che si aggiunge una nuova chiamata alla macro Q_OBJECT, è necessario eseguire nuovamente qmake. Il problema dei vtables a cui ti stai riferendo è direttamente correlato a questo.

Basta eseguire qmake e si dovrebbe andare bene supponendo che non ci siano altri problemi nel codice.

+16

All'interno di QT Creator, usa qmake dal menu Genera. –

+0

Grazie! Dalla riga di comando, l'uso di 'make' normalmente aggiorna anche alcune cose relative a qmake, ma apparentemente non abbastanza. È in effetti necessario eseguire 'qmake'. – Thomas

+0

L'esecuzione di qmake non è abbastanza per me, ho dovuto cancellare la mia cartella di build e ricompilare. – PaulrBear

2

Quando si ottiene una classe da QOBject (e si utilizza la macro Q_OBJECT), non dimenticare di definire e creare specificamente entrambe le classi del costruttore e del distruttore. Non è sufficiente usare il costruttore/distruttore predefinito del compilatore. I consigli sulla pulizia/esecuzione di qmake (e la cancellazione dei file moc_) sono ancora validi. Questo ha risolto il mio problema simile.

3

Per quanto mi riguarda, ho notato dai registri di costruzione che il moc non è stato chiamato.Clean All non ha aiutato. Così ho rimosso .pro.user, riavviato IDE e ha fatto il trucco.

26

Ho visto un sacco di modi per risolvere il problema, ma nessuna spiegazione sul perché accade, quindi ecco qui.

Quando il compilatore vede una classe con funzioni virtuali (dichiarate direttamente o ereditate), deve generare un vtable per quella classe. Poiché le classi sono generalmente definite nelle intestazioni (e quindi appaiono in più unità di traduzione), la domanda è dove posizionare il vtable.

In generale, il problema può essere risolto generando il vtable in ogni TU in cui è definita la classe, quindi consente al linker di eliminare i duplicati. Poiché le definizioni di classe devono essere uguali per ogni occorrenza da parte dell'ODR, ciò è sicuro. Tuttavia, rallenta anche la compilazione, blocca i file oggetto e richiede che il linker faccia più lavoro.

Come ottimizzazione, quindi, compilatori, quando possibile, scegliere una specifica TU per mettere il vtable in. Nel comune C++ ABI, questo TU è quella in cui la funzione fondamentale della classe è implementato in, dove la funzione chiave è la prima funzione membro virtuale dichiarata nella classe, ma non definita.

Nel caso di classi Qt, di solito iniziano con la macro Q_OBJECT, e questa macro contiene la dichiarazione

virtual const QMetaObject *metaObject() const; 

che, poiché è la prima funzione virtuale nella macro, sarà generalmente il primo funzione virtuale della classe e quindi la sua funzione chiave. Pertanto, il compilatore non emetterà il vtable nella maggior parte delle TU, solo quella che implementa metaObject. E l'implementazione di questa funzione viene scritta automaticamente da moc quando elabora l'intestazione. Pertanto, è necessario che l'moc elabori l'intestazione per generare un nuovo file cpp e quindi includa il file cpp nella compilation.

Quindi, quando si dispone di un nuovo header che definisce una classe -derived QObject, è necessario eseguire nuovamente qmake in modo che aggiorna i makefile per eseguire moc sulla nuova intestazione e compilare il file cpp risultante.

+6

Awesome write-up. Sto usando CMake invece di qmake, e vedo questo errore abbastanza frequentemente; è molto frustrante capire le informazioni basilari di C++ e non essere ancora in grado di capire cosa sta andando storto. Grazie! –

+0

@Kyle Strand non dovrebbe essere "impostato (CMAKE_AUTOMOC ON)" essere sufficiente? Ho una libreria Qt e devo eseguire 'qmake' ogni volta per evitare l'errore vtable. Significa che 'cmake' non sta eseguendo il' moc' come dovrebbe? –

+1

@JamesHirschorn Penseresti che dovrebbe essere sufficiente, sì. E infatti * appare * che 'moc' viene rieseguito per ogni build senza considerare se i file di input sono effettivamente cambiati. Non sono veramente sicuro di quale sia il problema fondamentale di CMake. –

0

Ho trovato un altro motivo per cui si potrebbe vedere questo - dal qmake parses attraverso i file di classe se li hai modificati in un modo non standard si potrebbe ottenere questo errore. Nel mio caso avevo una finestra di dialogo personalizzata ereditata da QDialog, ma volevo solo che fosse compilata ed eseguita durante la compilazione per Linux, non per Windows o OSX. Ho solo #ifdef __linux__ la classe in uscita, quindi non è stata compilata, ma in Linux, anche se è stato definito __linux__, il lancio era qmake.

1

Ho faticato con questo orario di errore. Risolto mettendo il file .cpp e .h in una cartella separata (!!). poi aggiunti la cartella nel file .pro: INCLUDEPATH + = $$ {_ _ PRO_FILE_PWD} /../ MyClasses/CMyClassWidget

e poi ha aggiunto il cpp e file .h. Finalmente funziona.

Problemi correlati