2012-11-28 14 views
5

Ho un'applicazione Qt con più classi che utilizzano segnali e slot e si compila bene. Tuttavia, quando creo una classe personalizzata all'interno del file CPP principale (main.cpp), viene visualizzato un errore del linker.Errore linker con segnale Qt/Esempio di slot

ecco il codice che uso:

class Counter : public QObject 
{ 
    Q_OBJECT 

public: 
    Counter() { m_value = 0; } 

    int value() const { return m_value; } 

public slots: 
    void setValue(int value) 
    { 
    if(value!=m_value) 
    { 
     m_value = value; 
     qDebug() << "Value " << value; 
     emit valueChanged(value); 
    } 
    } 

signals: 
    void valueChanged(int newValue); 

private: 
    int m_value; 
}; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 
    Counter a, b; 
    QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int))); 

    a.setValue(12);  // a.value() == 12, b.value() == 12 
    b.setValue(48);  // a.value() == 12, b.value() == 48 

    QTimer::singleShot(0, &app, SLOT(quit())); 

    return app.exec(); 
} 

Questi sono gli errori:

Error 4 error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall Counter::metaObject(void)const " ([email protected]@@[email protected]@XZ) 
Error 5 error LNK2001: unresolved external symbol "public: virtual void * __thiscall Counter::qt_metacast(char const *)" ([email protected]@@[email protected]) 
Error 6 error LNK2001: unresolved external symbol "public: virtual int __thiscall Counter::qt_metacall(enum QMetaObject::Call,int,void * *)" ([email protected]@@[email protected]@@[email protected]) 
Error 7 error LNK2019: unresolved external symbol "protected: void __thiscall Counter::valueChanged(int)" ([email protected]@@[email protected]) referenced in function "public: void __thiscall Counter::setValue(int)" ([email protected]@@[email protected]) 

errore Questo linker non si verifica quando ho posto il contatore in un file di intestazione separata. Qual è la ragione di questo comportamento?

risposta

5

Suppongo che tu stia lavorando con qmake.

Il moc viene eseguito automaticamente sui file di intestazione per impostazione predefinita, poiché in questo caso le classi vengono dichiarate in generale. Si noti che questa regola è definita nel makefile, è possibile eseguire manualmente moc su un file di origine.

È necessario informare qmake che il file contiene una classe. Per fare ciò, inserisci #include "filename.moc" dopo la dichiarazione di Counter. Puoi vedere maggiori dettagli here (QtCentre) o here (doc).

Se si lavora con un altro strumento di qmake, dire CMake, è necessario specificare una regola per forzare la moc per analizzare i file .cpp (il più semplice è di trattare tutti). Per i file che non contengono una classe di oggetti Qt, moc genererà un file vuoto.

Tuttavia, anche se questa classe è stata creata per essere "privata", si consiglia di dichiararla in un'intestazione (ad esempio counter_private.h). Ad esempio, la fonte Qt sta usando questo trucco.

1

Essi moc/UIC generazione personalizzata comandi vengono eseguiti sul file di intestazione, quindi compila quando viene messo in un file separato di intestazione/di origine e non quando viene messo nello stesso file sorgente

2

Sembra che tu hai solo un file di codice. Se si utilizza il modo predefinito per creare un progetto Qt build (qmake & & make o QtCreator), il MOC scansiona solo i file * .h. Se hai tutto il tuo codice in un main.cpp il MOC non creerà alcun codice, ma è necessario che Signal/Slot funzioni.

Il modo più semplice per rendere questo esempio specifico funzionante è l'aggiunta di una riga "#include" main.moc "" alla fine del main.cpp. Questa dipendenza verrà rilevata da qmake e verranno creati i target Makefile necessari.

Il modo più carino sarebbe quello pulito: Una classe: un'intestazione e un file di implementazione.