main.cppでのQObject派生クラスの記述方法

Qtの動作検証でmain.cppで適当にオブジェクトを定義してインスタンス化してコンパイルするとエラーが出てしまった。原因と対策がわかったので記す。

はじめに

Qtの勉強をしていて,動作を確認するために最小限のコードでコードを書いたりしている。

新しくクラスを作る場合,通常はヘッダー.hとソース.cppを用意して,ヘッダーをmain.cppで#includeして利用する。しかし,動作検証用にたかだが数行のコードを書くだけなのにファイルが2個も増えるのは煩雑だ。そこで,main.cppの冒頭にクラス宣言と定義を同時に書いて試そうとした。すると,以下のコンパイルエラーが出てしまった。

コンパイルエラー
main.cpp:3: undefined reference to `vtable for SingleDerivedQObject'

ヘッダーとソースを分けた場合にはこのコンパイルエラーが出なかった。原因がよくわからず,困ってしまった。調べてみたところ,以下の記事が見つかった。

これらの記事を参考にして原因と対策がわかったので,今後のために記しておく。

原因と対策

基本的に以下の記事に原因と対策が書かれていた。

Qt をはじめよう! 第11回: QObject の派生クラスを作成しよう – Qt Japanese Blog

Qtの基本クラスであるQObjectとその派生クラスから派生したクラスを作成する際に,定義の先頭でQ_OBJECTマクロを記述する。ヘッダーファイルであれば,qmake実行時に,自動的にQ_OBJECTマクロを検索して,必要に応じてmocコマンドを実行して,Qtに必要なメタオブジェクト情報を生成する。

しかし,ソースファイル(.cpp)に直接クラスをQObjectの派生クラスを定義した場合,qmakeが自動的に検索しにいかない。これがエラーの原因だった。

対策は,クラスの定義以降に以下のコードを記述すればいい。

#include "ソースファイル名(拡張子なし).moc"

この後,qmakeからビルドをやり直せば解決する。

動作検証コード

今回の問題の動作検証用コードを以下に用意した。

QtExample/SingleDerivedQObject at master · senooken/QtExample

短いので全文を以下にも掲載する。

SingleDerivedQObject.pro
QT += core
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp
main.cpp
#include <QCoreApplication>

class SingleDerivedQObject : public QObject
{
    Q_OBJECT
};

// This is required for derived QObject class in .cpp after class declaration.
#include "main.moc"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    SingleDerivedQObject object;
    return 0;
}

内容は,main.cppでQObjectから派生したSingleDerivedQObjectクラスを用意し,そのインスタンスを生成してプログラムを終了するというもの。ウィンドウや文字列の出力を一切行わない,動作検証用の最小限のコードとなっている。

main.cppで肝になっているのは,9行目の#include "main.moc"の記述だ。この記述が存在しない場合,以下のコンパイルエラーが出る。

コンパイルエラー(SingleDerivedQObject.log)
main.cpp:3: undefined reference to `vtable for SingleDerivedQObject'

今回はSingleDerivedQObjectクラスの定義直後にこのコードを記述したが,定義後であればどこでも大丈夫らしい。

おわりに

動作検証用にmain.cppでQObjectの派生クラスを定義するときに発生したコンパイルエラーの対処方法を記した。

こういう問題は原因と対処方法を調べるのがたいへんなので,今後同様の問題に遭遇したときの参考になればいい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

前の記事

QMLのデバッグ方法