2012-11-28 12 views
5

Ich habe eine Qt-Anwendung mit mehreren Klassen, die Signale und Slots verwenden und es kompiliert gut. Wenn ich jedoch eine benutzerdefinierte Klasse in der Haupt-CPP-Datei (main.cpp) erstelle, erhalte ich einen Linker-Fehler. HierLinker-Fehler mit Qt Signal/Slot Beispiel

ist der Code, den ich verwenden:

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(); 
} 

Hier sind die Fehler:

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]) 

Dieser Linker Fehler tritt nicht auf, wenn ich den Zähler in einem separaten Header-Datei platzieren. Was ist der Grund für dieses Verhalten?

Antwort

5

Ich nehme an, Sie mit qmake arbeiten.

Die moc wird auf die Header-Dateien standardmäßig automatisch ausgeführt werden, weil das ist, wo Klassen im Allgemeinen erklärt werden. Beachten Sie, dass diese Regel im Makefile definiert ist. Sie können moc manuell für eine Quelldatei ausführen.

Sie haben qmake zu informieren, dass die Datei eine Klasse enthält. Um dies zu tun, setzen Sie #include "filename.moc" nach der Deklaration von Counter. Sie können weitere Details here (QtCentre) oder here (doc) sehen. Wenn Sie mit einem anderen Werkzeug als qmake10 arbeiten, sagen Sie CMake, müssen Sie eine Regel angeben, die das Moc dazu zwingt, die .cpp Dateien zu parsen (am einfachsten ist es, sie alle zu verarbeiten). Für Dateien, die keine Qt-Objektklasse enthalten, generiert moc eine leere Datei.

Auch wenn diese Klasse als "privat" gekennzeichnet ist, rate ich Ihnen, sie in einer Kopfzeile zu deklarieren (zB counter_private.h). Zum Beispiel verwendet Qt-Quelle diesen Trick.

1

Sie moc/uic benutzerdefinierte Befehle auf der Header-Datei fertig bauen, so dass es, wenn sie in einer separaten Header/Quelldatei setzen kompiliert und nicht, wenn sie in der gleichen Quelldatei setzen

2

Es sieht aus wie Sie haben eine Codedatei Wenn Sie die Standardmethode zum Erstellen eines Qt-Projekt-Builds (qmake & & make oder QtCreator) verwenden, scannt das MOC nur * .h-Dateien. Wenn Sie Ihren gesamten Code in einer main.cpp haben, wird der MOC keinen Code erstellen, aber das wird benötigt, damit Signal/Slots funktionieren.

Der einfachste Weg, dieses spezifische Beispiel Arbeits eine Linie „#include‚main.moc‘“ am Ende Ihres main.cpp würde machen hinzuzufügen. Diese Abhängigkeit wird von qmake erkannt und die benötigten Makefile-Ziele werden erstellt.

Der netteste Weg wäre die saubere ein: Ein Klasse - One-Header und eine Implementierungsdatei.