如果 .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'
这似乎是完全相同的代码。为什么当代码位于标题中时它会链接,而其他情况下它不会链接?
This code compiles, links and works as intended:
#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();
}
But when I put the class definition in .cpp
file instead of header files, I get linker errors stating that vtable
was not properly defined.
#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'
This seems to be exactly the same code. Why does it link when the code is in headers and it doesn't link otherwise?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Qt 使用
moc
工具来处理所需的 C++ 扩展,例如信号槽机制。该工具处理项目中的所有头 (!) 文件,并生成新的源文件,其中包含那些包含Q_OBJECT
宏的类的元对象代码。当您在
.cpp
文件而不是.h
文件中定义类时,moc
无法正确处理它。有关 Qt 元对象编译器的更多信息,请参阅本文。
Qt uses
moc
tool to handle C++ extensions that a required, for example, for signals-slots mechanism. This tool processes all header (!) files in the project and generates new source files that contain meta-object code for those classes that containQ_OBJECT
macro.When you have your class defined in
.cpp
file instead of.h
filemoc
fails to process it properly.Have a look at this article for more information about Qt Meta-Object Compiler.
链接器抱怨缺少编译 moc 输出的目标代码。这是因为虽然 moc 已经处理了源文件,但其输出并未编译成目标文件。
对于头文件,构建系统假定它们旨在包含在多个翻译单元中,并且不会违反单一定义规则。因此,moc 输出可以包含头文件,并编译为独立的翻译单元。
但是,如果
.cpp
文件中有任何Q_OBJECT
宏,则无法单独编译 moc 输出:它将无法访问中的声明>.cpp
文件,因此无法编译!它还不能包含您的.cpp
文件,因为这会违反单一定义规则 :两个翻译单元 - moc 输出和您的.cpp
文件 - 将定义相同的内容。相反,您需要将 moc 的输出附加到
.cpp
文件的末尾。例如,如果main.cpp
中有O_OBJECT
,则在文件末尾添加#include "main.moc"
:上面是SSCCE。
有人可能会说,也许 qmake/cmake 应该设置构建,以便 moc 输出在发送到编译器之前自动附加到
.cpp
文件中。到目前为止,该功能尚未实现。The linker is complaining about missing the object code that comes from compiling moc output. That's because although moc has processed the source file, its output was not compiled into an object file.
For header files, the build system assumes that they are meant for inclusion in multiple translation units and won't violate the one definition rule. Thus moc output can include the header file, and get compiled as a stand-alone translation unit.
But, if you have any
Q_OBJECT
macros within a.cpp
file, the moc output cannot be compiled in isolation: it won't have access to the declarations from your.cpp
file and thus can't compile! It also can't include your.cpp
file, since that would violate the one definition rule: two translation units - moc output and your.cpp
file - would define the same stuff.Instead, you need to append moc's output to the end of the
.cpp
file. E.g., if you haveO_OBJECT
inmain.cpp
, add#include "main.moc"
at the end of the file:The above is an SSCCE.
One could argue that perhaps qmake/cmake should set up the build so that moc output is automatically appended to the
.cpp
file before it's sent to the compiler. So far, that feature is not implemented.