该代码按预期编译,链接和工作:

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

但是当我将课堂定义放在 .cpp 文件而不是标题文件,我得到链接器错误,说明 vtable 未正确定义。

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

这似乎是完全相同的代码。为什么当代码在标题中并且没有其他链接时链接?

有帮助吗?

解决方案

QT使用 moc 处理C ++扩展的工具,例如信号插槽机制所需的工具。该工具处理项目中的所有标题(!)文件,并生成新的源文件,这些文件包含那些包含的类的元对象代码 Q_OBJECT 宏。

当您的课程定义时 .cpp 文件而不是 .h 文件 moc 无法正确处理。

看一下 本文 有关QT Meta-Object编译器的更多信息。

其他提示

因为QT在标题文件上运行MOC,并且不会在源上运行它。

链接器抱怨丢失来自编译MOC输出的对象代码。这是因为尽管MOC已经处理了源文件,但其输出未编译到对象文件中。

对于标题文件,构建系统假定它们是为了包含在多个翻译单元中,并且不会违反 一个定义规则. 。因此,MOC输出可以包括标头文件,并作为独立翻译单元进行编译。

但是,如果您有 Q_OBJECT 宏中的宏 .cpp 文件,MOC输出不能孤立地编译:它无法访问您的声明 .cpp 文件,因此无法编译!它也不能包括您的 .cpp 文件,因为那会违反 一个定义规则: :两个翻译单元 - MOC输出和您的 .cpp 文件 - 将定义相同的内容。

相反,您需要将MOC的输出附加到 .cpp 文件。例如,如果你有 O_OBJECTmain.cpp, , 添加 #include "main.moc" 在文件的末尾:

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

以上是 SSCCE.

有人可能会争辩说,也许QMAKE/CMAKE应该设置构建,以便将MOC输出自动附加到 .cpp 在将其发送给编译器之前文件。到目前为止,该功能尚未实现。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top