.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がソースファイルを処理したが、その出力がオブジェクトファイルにコンパイルされていないためです。
ヘッダーファイルの場合、ビルドシステムは、複数の翻訳ユニットに含めることを目的としており、 1つの定義ルール. 。したがって、MOC出力にはヘッダーファイルを含めることができ、スタンドアロンの翻訳ユニットとしてコンパイルされます。
しかし、あなたが持っているなら Q_OBJECT
a内のマクロ .cpp
ファイル、MOC出力は単独でコンパイルできません:それはあなたからの宣言にアクセスできません .cpp
ファイルするので、コンパイルできません!また、あなたを含めることはできません .cpp
ファイルは、それが違反するためです 1つの定義ルール: :2つの翻訳ユニット - 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
コンパイラに送信される前にファイル。これまでのところ、その機能は実装されていません。