Warum verknüpft mein Projekt nicht, wenn es in .cpp -Dateien q_object -Makros gibt?

StackOverflow https://stackoverflow.com/questions/8307059

  •  25-10-2019
  •  | 
  •  

Frage

Dieser Code kompiliert, verlinkt und funktioniert wie beabsichtigt:

#include <QApplication>
#include <QListView>
#include "File_List_Model.h"

int main(int c,char**v)
{
    QApplication app(c,v);
    QStringList list;

    list << "a" << "b" << "c";

    File_List_Model* model = new File_List_Model;
    model->set_entries(list);

    QListView* view = new QListView;
    view->setModel(model);
    view->show();

    return app.exec();
} 

Aber wenn ich die Klassendefinition einsehe .cpp Datei anstelle von Header -Dateien erhalte ich Linkerfehler, die dies sagen vtable wurde nicht richtig definiert.

#include <QApplication>
#include <QListView>
//#include "File_List_Model.h"
#include "File_List_Proxy.h"
#include <QAbstractItemModel>
#include <QStringList>

class File_List_Model : public QAbstractItemModel
{
    Q_OBJECT
private:
    QStringList data_;
public:
    File_List_Model(QObject *parent = 0) :
        QAbstractItemModel(parent)
    {
    }

    int columnCount(const QModelIndex& parent) const
    {
        return 1;
    }

    QVariant data(const QModelIndex & index, int role) const
    {
        switch(role)
        {
            case Qt::DisplayRole:
            return data_[index.row()];
        default:
            return QVariant();
        }
    }

     QModelIndex index(int row, int column, const QModelIndex & parent) const
    {
        return createIndex(row,column);
    }

    QModelIndex parent(const QModelIndex & index) const
    {
        return QModelIndex();
    }

     bool set_entries(const QStringList& entries)
     {
         if (entries.size())
         {
         beginInsertRows(createIndex(0,0),0,entries.size());
         data_ = entries;
         endInsertRows();
         emit dataChanged(createIndex(0,0),createIndex(0,entries.size()));
         return true;
         }
         else
         {
             return false;
         }
     }

     int rowCount(const QModelIndex & parent) const
     {
         return data_.size();
     }


};

int main(int c,char**v)
{
    QApplication app(c,v);
    QStringList list;

    list << "a" << "b" << "c";

    File_List_Model* model = new File_List_Model;
    model->set_entries(list);

    File_List_Proxy* proxy = new File_List_Proxy;
    proxy->setSourceModel(model);

    QListView* view = new QListView;
    view->setModel(proxy);
    view->show();

    return app.exec();
}
//error:   
debug/moc_File_List_Model.o:moc_File_List_Model.cpp:(.rdata$_ZTV15File_List_Model[vtable for File_List_Model]+0x44): undefined reference to `File_List_Model::columnCount(QModelIndex const&) const'
debug/moc_File_List_Model.o:moc_File_List_Model.cpp:(.rdata$_ZTV15File_List_Model[vtable for File_List_Model]+0x4c): undefined reference to `File_List_Model::data(QModelIndex const&, int) const'

Dies scheint genau der gleiche Code zu sein. Warum verlinkt es, wenn sich der Code in den Headern befindet und sonst nicht verknüpft?

War es hilfreich?

Lösung

Qt verwendet moc Werkzeug zur Verarbeitung von C ++-Erweiterungen, die beispielsweise für den Signal-Slots-Mechanismus erforderlich sind. Dieses Tool verarbeitet alle Header-Dateien (!) Dateien im Projekt und generiert neue Quelldateien, die Meta-Objekt-Code für die Klassen enthalten, die enthalten Q_OBJECT Makro.

Wenn Sie Ihre Klasse in definiert haben .cpp Datei statt von .h Datei moc verarbeitet es nicht richtig.

Sich ansehen Dieser Artikel Weitere Informationen zum QT-Meta-Objekt-Compiler.

Andere Tipps

Da QT MOC auf Header -Dateien ausführt und es nicht auf Quellen ausführt.

Der Linker beschwert sich darüber, dass der Objektcode, der aus dem Kompilieren von MOC -Ausgaben entsteht. Dies liegt daran, dass MOC die Quelldatei verarbeitet hat, ihre Ausgabe nicht in eine Objektdatei zusammengestellt wurde.

Für Header -Dateien geht das Build -System davon aus eine Definitionsregel. Somit kann die MOC-Ausgabe die Header-Datei enthalten und als eigenständige Übersetzungseinheit kompiliert werden.

Aber wenn Sie welche haben Q_OBJECT Makros innerhalb von a .cpp Datei, die MOC -Ausgabe kann nicht isoliert kompiliert werden: Sie hat keinen Zugriff auf die Erklärungen von Ihrem .cpp Datei und kann also nicht kompilieren! Es kann auch Ihre nicht enthalten .cpp Datei, da dies gegen die verstoßen würde eine Definitionsregel: Zwei Übersetzungseinheiten - MOC -Ausgabe und Ihre .cpp Datei - würde das gleiche Zeug definieren.

Stattdessen müssen Sie die Ausgabe von MOC an das Ende der anhängen .cpp Datei. ZB, wenn Sie haben O_OBJECT in main.cpp, hinzufügen #include "main.moc" Am Ende der Datei:

// main.cpp
#include <QtCore>

struct Object : QObject {
  Q_OBJECT
};

int main() {
  Object o;
  qDebug() << o.metaObject()->className();
}

#include "main.moc"
// "main.moc" depends on the declaration of Object above!

Das obige ist ein SSCCE.

Man könnte argumentieren, dass QMake/CMake den Build möglicherweise so einrichten sollte, dass die MOC -Ausgabe automatisch an die angehängt wird .cpp Datei, bevor es an den Compiler gesendet wird. Bisher wird diese Funktion nicht implementiert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top