此代码按预期编译,链接和工作:
#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'
这似乎是完全相同的代码。当代码在标题中时为什么会链接,否则它没有链接?
答案 0 :(得分:3)
Qt使用moc
工具来处理所需的C ++扩展,例如,信号槽机制。此工具处理项目中的所有头文件(!),并生成包含元对象代码的新源文件,这些代码包含Q_OBJECT
宏的类。
如果您在.cpp
文件中定义了类,而不是.h
文件moc
无法正确处理它。
有关Qt元对象编译器的更多信息,请查看this article。
答案 1 :(得分:0)
因为Qt在头文件上运行moc而不在源文件上运行它。
答案 2 :(得分:-1)
链接器抱怨缺少编译moc输出的目标代码。那是因为虽然moc已经处理了源文件,但是它的输出没有被编译成目标文件。
对于头文件,构建系统假定它们包含在多个翻译单元中,并且不会违反one definition rule。因此,moc输出可以包含头文件,并编译为独立的转换单元。
但是,如果Q_OBJECT
文件中有任何.cpp
个宏,则无法单独编译moc输出:它无法访问.cpp
文件中的声明因此无法编译!它也不能包含您的.cpp
文件,因为这会违反one definition rule:两个翻译单元--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
文件。到目前为止,该功能尚未实施。