如果.cpp文件中有q_object宏,为什么我的项目不链接?
题
该代码按预期编译,链接和工作:
#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_OBJECT
在 main.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
在将其发送给编译器之前文件。到目前为止,该功能尚未实现。