Meta-Object Compiler (moc)の使用
Meta-Object Compiler (moc )は、QtのC++拡張機能を処理するプログラムです。
moc ツールは、C++ ヘッダーファイルを読み込みます。Q_OBJECT マクロを含むクラス宣言を 1 つ以上見つけた場合、そのクラス用のメタオブジェクトコードを含む C++ ソースファイルを生成します。メタオブジェクトコードは、シグナルとスロットのメカニズム、実行時の型情報、動的プロパティシステムなどに必要とされます。
moc によって生成された C++ ソースファイルは、コンパイルされ、クラスの実装とリンクされる必要があります。
qmake とCMakeはどちらも、moc を適切に呼び出すビルドルールを含むmakefileを生成するため、moc を直接使用する必要はありません。qmake ではデフォルトでこれらのビルドルールが追加されますが、CMakeではAUTOMOCプロパティを使用してmoc を自動的に処理できます。moc に関する詳細な背景情報については、「QtはなぜシグナルとスロットにMocを使用するのか?」を参照してください。
使用方法
moc は通常、次のようなクラス宣言を含む入力ファイルとともに使用されます:
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject *parent = 0);
~MyClass();
signals:
void mySignal();
public slots:
void mySlot();
};上記のシグナルやスロットに加え、moc は次の例のようにオブジェクトプロパティも実装しています。Q_PROPERTY() マクロはオブジェクトプロパティを宣言し、Q_ENUM()はプロパティシステム内で使用できるように、クラス内の列挙型のリストを宣言します。
次の例では、列挙型 `Priority ` のプロパティを宣言しています。このプロパティも `priority ` と呼ばれ、get関数 `priority() ` とset関数 `setPriority()` を持っています。
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(Priority priority READ priority WRITE setPriority)
public:
enum Priority { High, Low, VeryHigh, VeryLow };
Q_ENUM(Priority)
MyClass(QObject *parent = 0);
~MyClass();
void setPriority(Priority priority) { m_priority = priority; }
Priority priority() const { return m_priority; }
private:
Priority m_priority;
};Q_FLAG() マクロは、フラグとして、つまり OR 演算で結合して使用される列挙型を宣言します。もう 1 つのマクロであるQ_CLASSINFO() を使用すると、クラスのメタオブジェクトに追加の名前/値のペアを関連付けることができます。
class MyClass : public QObject
{
Q_OBJECT
Q_CLASSINFO("Author", "Oscar Peterson")
Q_CLASSINFO("Status", "Active")
public:
MyClass(QObject *parent = 0);
~MyClass();
};moc によって生成された出力は、プログラム内の他のC++コードと同様にコンパイルおよびリンクする必要があります。そうしないと、ビルドは最終的なリンク段階で失敗します。qmake を使用する場合、この処理は自動的に行われます。qmake が実行されるたびに、プロジェクトのヘッダーファイルを解析し、Q_OBJECT マクロを含むファイルに対してmoc を呼び出すmakeルールを生成します。同様に、AUTOMOCを ON に設定すると、CMakeはビルド時にヘッダーファイルとソースファイルをスキャンし、それに応じてmoc を呼び出します。
ファイル `myclass.h` にクラス宣言が見つかった場合、mocの出力は `moc_myclass.cpp` という名前のファイルに格納されるべきです。このファイルは通常通りコンパイルされ、オブジェクトファイル(Windowsの場合、例えば `moc_myclass.obj `)が生成されます。このオブジェクトファイルは、プログラムの最終ビルド段階でリンクされるオブジェクトファイルのリストに含める必要があります。
呼び出し用の Make ルールの記述moc
ごく単純なテストプログラム以外の場合、moc の実行を自動化することをお勧めします。プログラムのMakefileにいくつかのルールを追加することで、make が必要に応じてmocを実行し、mocの出力を適切に処理できるようになります。
CMakeやqmakeを使用すれば、moc の処理に必要なすべての処理を行う makefile を生成できます。
自分で makefile を作成したい場合は、moc の処理を組み込むためのヒントを以下に示します。
ヘッダーファイル内のQ_OBJECT クラス宣言について、GNU make のみを使用する場合に役立つ makefile ルールは以下の通りです:
moc_%.cpp: %.h
moc $(DEFINES) $(INCPATH) $< -o $@移植性を考慮して記述したい場合は、次のような形式の個別のルールを使用できます:
moc_foo.cpp: foo.h
moc $(DEFINES) $(INCPATH) $< -o $@また、SOURCES (お好みの名前に置き換えてください)変数にmoc_foo.cpp を追加し、OBJECTS 変数にmoc_foo.o またはmoc_foo.obj を追加することを忘れないでください。
どちらの例も、$(DEFINES) および$(INCPATH) が、C++ コンパイラに渡される定義およびインクルードパスのオプションに展開されることを前提としています。これらは、moc がソースファイルをプリプロセスするために必要です。
C++ソースファイルの拡張子としては.cpp を推奨しますが、必要に応じて.C 、.cc 、.CC 、.cxx 、.c++ などの他の拡張子を使用することも可能です。
実装ファイル(.cpp )内のQ_OBJECT クラス宣言については、次のようなmakefileルールを推奨します:
foo.o: foo.moc
foo.moc: foo.cpp
moc $(DEFINES) $(INCPATH) -i $< -o $@これにより、make がfoo.cpp をコンパイルする前に moc を実行することが保証されます。その後、
#include "foo.moc"foo.cpp の末尾に記述できます。この時点では、そのファイルで宣言されたすべてのクラスが完全に把握されている状態です。
コマンドラインオプション
moc がサポートするコマンドラインオプションは以下の通りです:
| オプション | 説明 |
|---|---|
-D<macro>[=<def>] | マクロを定義します。定義は省略可能です。 |
-E | プリプロセス専用。メタオブジェクトコードは生成しない。 |
-f[<file>] | 出力に `#include ` ステートメントの生成を強制します。これは、拡張子が `H ` または `h` で始まるヘッダーファイルのデフォルト設定です。このオプションは、標準の命名規則に従っていないヘッダーファイルがある場合に役立ちます。`<file> ` の部分は省略可能です。 |
-Fdir | macOS。ヘッダーファイルの検索対象ディレクトリ一覧の先頭に、フレームワークディレクトリ `dir ` を追加します。これらのディレクトリは `-I` オプションで指定されたディレクトリと交互に配置され、左から右の順にスキャンされます(gcc のマニュアルページを参照)。通常は、`-F /Library/Frameworks/` を使用します。 |
-h | 使用方法とオプションの一覧を表示します。 |
-i | 出力に `#include ` ステートメントを生成しない。これは、1つ以上のクラス宣言を含むC++ファイルに対してmocを実行する場合に使用できます。その場合、.cpp ファイル内のメタオブジェクトコードを `#include ` する必要があります。 |
-I<dir> | ヘッダーファイルのインクルードパスに dir を追加します。 |
-M<key=value> | プラグインに追加のメタデータを付加します。クラスにQ_PLUGIN_METADATA が指定されている場合、キーと値のペアがそのメタデータに追加されます。これは、実行時にプラグイン用に解決されるJsonオブジェクトに含まれることになります(QPluginLoader からアクセス可能)。この引数は通常、ビルドシステムによって解決された情報を静的プラグインにタグ付けするために使用されます。 |
-nw | 警告を一切生成しない。(推奨されません。) |
-o<file> | 標準出力ではなく、<file> に出力を書き込みます。 |
-p<path> | moc が生成する#include ステートメント内のファイル名の先頭に<path>/ を付加するようにします。 |
-U<macro> | マクロを未定義にします。 |
@<file> | <file> から追加のコマンドラインオプションを読み込みます。ファイルの各行は単一のオプションとして扱われます。空行は無視されます。このオプションは、オプションファイル自体ではサポートされていないことに注意してください(つまり、オプションファイルは別のファイルを「インクルード」することはできません)。 |
-v | moc のバージョン番号を表示します。 |
ヘッダーファイルの一部を解析しないよう、moc に明示的に指示することができます。moc は、プリプロセッサシンボル `Q_MOC_RUN` を定義しています。`#include` で囲まれたコードは、
#ifndef Q_MOC_RUN
...
#endifで囲まれたコードは、moc によってスキップされます。
診断
moc は、Q_OBJECT のクラス宣言に含まれる危険または不正な構文について警告を出します。
プログラムの最終ビルド段階で、YourClass::className() が未定義である、あるいはYourClass に vtable が欠けているというリンクエラーが発生した場合は、何か間違った操作が行われたことになります。 ほとんどの場合、mocによって生成されたC++コードをコンパイルまたは#include するのを忘れているか、あるいは(前者の場合)リンクコマンドにそのオブジェクトファイルを含めるのを忘れています。qmake を使用している場合は、それを再実行してmakefileを更新してみてください。これで問題は解決するはずです。
ビルドシステム
ヘッダー moc ファイルのインクルード
qmakeとCMakeは、ヘッダー用mocファイルのインクルードに関して異なる挙動を示します。
例を挙げて説明すると、対応するソースファイルを持つ 2 つのヘッダーファイルがあるとします:a.h 、a.cpp 、b.h 、およびb.cpp 。各ヘッダーには、Q_OBJECT というマクロが含まれています:
// a.h
class A : public QObject
{
Q_OBJECT
public:
// ...
};// a.cpp
#include "a.h"
// ...
#include "moc_a.cpp"// b.h
class B : public QObject
{
Q_OBJECT
public:
// ...
};// b.cpp
#include "b.h"
// ...
#include "moc_b.cpp"qmake を使用する場合、moc によって生成されたファイル(moc_a.cpp/moc_b.cpp )を含めないでいると、a.cpp 、b.cpp 、moc_a.cpp 、およびmoc_b.cpp が個別にコンパイルされます。これにより、ビルド時間が長くなる可能性があります。moc によって生成されたファイルを含める場合、moc によって生成されたコードはそれらのファイルにインクルードされているため、コンパイルが必要なのは a.cpp と b.cpp のみとなります。
CMake では、これらのファイルをインクルードしない場合、moc によって 1 つの追加ファイル(例としてcmake.cpp としましょう)が生成されます。cmake.cpp と記述すると、moc_a.cpp とmoc_b.cpp の両方がインクルードされます。CMake では moc によって生成されたファイルをインクルードすることも可能ですが、必ずしも必要というわけではありません。
このトピックに関する CMake の moc サポートの詳細については、「ソースへのヘッダー moc ファイルのインクルード」を参照してください。
制限事項
moc は C++ のすべてを扱えるわけではありません。主な問題は、クラステンプレートに `Q_OBJECT ` マクロを使用できないことです。例を以下に示します:
class SomeTemplate<int> : public QFrame
{
Q_OBJECT
...
signals:
void mySignal(int);
};以下の構文は不正です。これらすべてには、通常はより良いとされる代替手段があるため、これらの制限の解消は当方にとって優先度は高くありません。
多重継承では、QObjectを最初に指定する必要がある
多重継承を使用する場合、moc は、最初に継承されるクラスがQObject のサブクラスであることを前提としています。また、最初に継承されるクラスだけがQObject であることを確認してください。
// correct
class SomeClass : public QObject, public OtherClass
{
...
};QObject での仮想継承はサポートされていません。
関数ポインタはシグナルやスロットのパラメータとして使用できません
関数ポインタをシグナルやスロットのパラメータとして使用することを検討するほとんどのケースにおいて、継承の方がより適切な代替手段であると考えます。以下に、不正な構文の例を示します。
class SomeClass : public QObject
{
Q_OBJECT
public slots:
void apply(void (*apply)(List *, void *), char *); // WRONG
};この制限は、次のように回避できます:
typedef void (*ApplyFunction)(List *, void *);
class SomeClass : public QObject
{
Q_OBJECT
public slots:
void apply(ApplyFunction, char *);
};場合によっては、関数ポインタを継承や仮想関数に置き換えたほうがさらに良い結果が得られることもあります。
シグナルおよびスロットのパラメータとして使用する列挙型およびtypedefは、完全修飾名で指定する必要があります
QObject::connect() は引数のシグネチャをチェックする際、データ型を文字通り比較します。したがって、Alignment とQt::Alignment は 2 つの異なる型として扱われます。この制限を回避するには、シグナルやスロットを宣言する際、および接続を確立する際に、データ型を完全修飾するようにしてください。例:
class MyClass : public QObject
{
Q_OBJECT
enum Error {
ConnectionRefused,
RemoteHostClosed,
UnknownError
};
signals:
void stateChanged(MyClass::Error error);
};ネストされたクラスにはシグナルやスロットを設定できない
以下に、問題となる構文の例を示します:
class A
{
public:
class B
{
Q_OBJECT
public slots: // WRONG
void b();
};
};シグナル/スロットの戻り値型は参照型にできない
シグナルやスロットには戻り値型を指定できますが、参照を返すシグナルやスロットは void を返すものとして扱われます。
クラスの `signals ` および `slots ` セクションにはシグナルとスロットのみ記述可能
moc クラスのsignals やslots セクションに、シグナルやスロット以外の構文を記述しようとすると、エラーが発生します。
「メタオブジェクトシステム」、「シグナルとスロット」、および「Qtのプロパティシステム」も参照してください 。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.