Pourquoi mon projet ne lie pas s'il y a des macros Q_OBJECT dans les fichiers .cpp?

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

  •  25-10-2019
  •  | 
  •  

Question

Ce code se compile, des liens et fonctionne comme prévu:

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

Mais quand je mets la définition de classe dans le fichier .cpp au lieu des fichiers d'en-tête, je reçois des erreurs de l'éditeur de liens indiquant que vtable n'a pas été correctement défini.

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

Cela semble être exactement le même code. Pourquoi faut-il un lien lorsque le code est en-têtes et il ne lie pas autrement?

Était-ce utile?

La solution

Qt utilise l'outil de moc pour gérer les extensions de C qui a besoin, par exemple, pour le mécanisme des signaux de fentes. Cet outil traite tous les fichiers d'en-tête (!) Dans le projet et génère de nouveaux fichiers source qui contiennent du code méta-objet pour les classes qui contiennent macro Q_OBJECT.

Lorsque vous avez votre classe définie dans le fichier .cpp au lieu de fichier .h moc ne parvient pas à traiter correctement.

Jetez un oeil à cet article pour plus d'informations sur Qt Meta-Object compilateur.

Autres conseils

Parce que Qt fonctionne sur moc fichiers d'en-tête et ne fonctionnent pas sur les sources.

L'éditeur de liens se plaint de manquer le code objet qui vient de la compilation sortie moc. En effet, bien que moc a traité le fichier source, sa sortie n'a pas été compilé dans un fichier objet.

Pour les fichiers d'en-tête, le système de construction suppose qu'ils sont destinés à inclure dans plusieurs unités de traduction et ne viole pas la une règle de définition . Ainsi, la sortie moc peut inclure le fichier d'en-tête et obtenir compilé comme une unité de traduction autonome.

Mais, si vous avez des macros Q_OBJECT dans un fichier .cpp, la sortie de moc ne peut pas être compilé de manière isolée: il ne sera pas avoir accès aux déclarations de votre fichier .cpp et ne peut donc pas compiler! Il ne peut pas inclure également votre fichier .cpp, car cela violerait la une règle définition : deux unités de traduction - sortie moc et votre fichier .cpp -. définirait la même chose

, vous devez ajouter au lieu de la sortie de moc à la fin du fichier .cpp. Par exemple, si vous avez O_OBJECT à main.cpp, ajouter #include "main.moc" à la fin du fichier:

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

Ce qui précède est une SSCCE .

On pourrait dire que qmake / cmake peut-être devrait mettre en place la construction de telle sorte que la sortie de moc est automatiquement ajouté au fichier .cpp avant qu'il ne soit envoyé au compilateur. Jusqu'à présent, cette fonctionnalité ne soit pas mise en œuvre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top