Perchè il mio progetto non si collega se ci sono le macro Q_OBJECT nei file cpp?

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

  •  25-10-2019
  •  | 
  •  

Domanda

Questo codice viene compilato, link e funziona come previsto:

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

Ma quando ho messo la definizione di classe nel file di .cpp al posto di file header, ricevo errori del linker affermando che vtable non è stato correttamente definito.

#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'

Questo sembra essere esattamente lo stesso codice. Perché lo fa collegamento quando il codice è nelle intestazioni e non collega altrimenti?

È stato utile?

Soluzione

Qt utilizza strumento moc per gestire C ++ estensioni che un necessario, ad esempio, per il meccanismo di segnali-slots. Questo strumento elabora tutti intestazione (!) I file del progetto e genera nuovi file di origine che contengono il codice meta-oggetto per quelle classi che contengono Q_OBJECT macro.

Una volta la classe definita nel file di .cpp invece di file di .h moc non riesce a elaborare in modo corretto.

Date un'occhiata al questo articolo per ulteriori informazioni su Qt Meta-Object Compiler.

Altri suggerimenti

A causa Qt viene eseguito moc sul file di intestazione e non eseguirlo su fonti.

Il linker si lamenta di perdere il codice oggetto che viene dalla compilazione di uscita moc. Questo perché, anche se MOC ha elaborato il file di origine, la sua uscita non è stato compilato in un file oggetto.

Per i file di intestazione, il sistema di compilazione presume che essi sono destinati per l'inclusione in più unità di traduzione e non violerà la una regola definizione . Così uscita MOC può includere il file di intestazione, e ottenere compilato come un'unità di traduzione stand-alone.

Ma, se avete le macro Q_OBJECT all'interno di un file .cpp, l'uscita moc non può essere compilato in modo isolato: esso non avrà accesso alle dichiarazioni dal file .cpp e quindi non può compilare! Inoltre, non può includere il file .cpp, in quanto ciò violerebbe la una definizione di regola : due unità di traduzione - uscita moc e il file .cpp -. definirebbe la stessa roba

Al contrario, è necessario aggiungere l'output di moc alla fine del file .cpp. Per esempio, se avete O_OBJECT in main.cpp, aggiungere #include "main.moc" alla fine del file:

// 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!

È possibile che questo è un SSCCE .

Si potrebbe obiettare che forse qmake / cmake dovrebbe impostare la compilazione in modo che l'uscita moc viene aggiunto automaticamente al file .cpp prima di essere inviato al compilatore. Finora, questa funzione non è implementata.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top