Pregunta

Este código compila, enlaza y funciona según lo 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();
} 

Pero cuando pongo la definición de clase en .cpp Archivo En lugar de archivos de encabezado, obtengo errores de enlace que indican que vtable no se definió correctamente.

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

Este parece ser exactamente el mismo código. ¿Por qué vincula cuando el código está en encabezados y no vincula de otra manera?

¿Fue útil?

Solución

QT usa moc Herramienta para manejar las extensiones de C ++ que requerían, por ejemplo, para el mecanismo de lotes de señales. Esta herramienta procesa todos los archivos de encabezado (!) En el proyecto y genera nuevos archivos de origen que contienen código de meta-objeto para aquellas clases que contienen Q_OBJECT macro.

Cuando tienes tu clase definida en .cpp archivo en lugar de .h expediente moc no lo puede procesar correctamente.

Mira esto Este artículo Para obtener más información sobre el compilador de meta-objeto QT.

Otros consejos

Porque QT ejecuta MOC en archivos de encabezado y no lo ejecute en fuentes.

El enlazador se queja de perder el código de objeto que proviene de compilar la salida MOC. Esto se debe a que aunque MOC ha procesado el archivo fuente, su salida no se compiló en un archivo de objeto.

Para los archivos de encabezado, el sistema de compilación supone que están destinados a su inclusión en múltiples unidades de traducción y no violarán el regla de definición. Por lo tanto, la salida MOC puede incluir el archivo de encabezado y ser compilado como una unidad de traducción independiente.

Pero, si tienes alguna Q_OBJECT macros dentro de un .cpp Archivo, la salida MOC no se puede compilar de forma aislada: no tendrá acceso a las declaraciones de su .cpp Archivo y, por lo tanto, no se puede compilar! Tampoco puede incluir tu .cpp archivo, ya que eso violaría el regla de definición: Dos unidades de traducción: salida MOC y tu .cpp Archivo: definiría las mismas cosas.

En su lugar, debe agregar la salida de MOC al final del .cpp expediente. Por ejemplo, si tienes O_OBJECT en main.cpp, agregar #include "main.moc" Al final del archivo:

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

Lo anterior es un SSCCE.

Se podría argumentar que quizás Qmake/CMake debería configurar la compilación para que la salida MOC se agrega automáticamente al .cpp archivo antes de que se envíe al compilador. Hasta ahora, esa característica no se implementa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top