Qtのメタオブジェクトシステム(メタオブジェクト)(2)、mocの使用

公式文書から翻訳この記事。

MOC(MOC)を使用します

  MOC MOCは、QtののC ++プログラム処理の延長です。MOCツールは、C ++のヘッダファイルを読み込みます。それは、1つ以上のクラス宣言は、Q_OBJECTマクロを含む検出された場合、それは、これらのクラスのオブジェクトコード要素を含むC ++ソースファイルを生成します。加えて、シグナルとスロット機構、及び動的ランタイムタイプ情報要素オブジェクトは、システムコードを必要とする属性。MOC C ++のソースファイルによって生成されたがコンパイルされ、実装クラスとリンクする必要があります。
  あなたがメイクファイルを作成するためにqmakeのを使用している場合は、直接MOCを使用する必要はありませんので、構築ルールは、ルールに必要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()()マクロは、オブジェクトのプロパティを宣言するには、プロパティシステムを使用することができ、クラスで列挙型のリストを宣言します。以下の例では、優先度属性の列挙型はまた、優先順位と呼ばれ、優先機能GET()を有し、関数setPriorityを設定されている宣言()。

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority)
    Q_ENUMS(Priority)

public:
    enum Priority { High, Low, VeryHigh, VeryLow };

    MyClass(QObject *parent = 0);
    ~MyClass();

    void setPriority(Priority priority) { m_priority = priority; }
    Priority priority() const { return m_priority; }

private:
    Priority m_priority;
};

  Q_FLAGS()マクロは、列挙標識、即ちOR演算子として使用されるように宣言する。別のマクロQ_CLASSINFOは()を使用すると、メタオブジェクトのクラスに付加される名前/値のペアを添付することができます:

class MyClass : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("Author", "Oscar Peterson")
    Q_CLASSINFO("Status", "Active")

public:
    MyClass(QObject *parent = 0);
    ~MyClass();
};

  ちょうど同じのプログラム内の他のC ++コードのように、MOC C ++ファイルによって生成されたコンパイルとリンクしなければならない、そうでない場合、ビルドは最後のリンク段階で失敗します。あなたがqmakeのを使用している場合は、それが自動的に行われます。qmakeのを実行するたびに、MOCファイルを呼び出すためのルールを作るプロジェクトのヘッダファイルを解析し、生成されますQ_OBJECTマクロが含まれています。あなたはmyclass.hファイルにクラス宣言を見つけた場合、それはでmoc_myclass.cppという名前のファイルに出力をMOC必要があります。その後、Windows上でmoc_myclass.obj例えば、ターゲットファイルを生成するために、通常、このファイルとしてコンパイルする必要があります。その後、オブジェクトが一緒にプログラムを構築する最終段階でオブジェクトファイルのリストが含まれている必要があります。

MOCを呼び出すためのルールを書きます

  最も簡単なテスト手順に加えて、我々はあなたが自動的にmocを実行することをお勧めします。メイクファイルのプログラムにいくつかのルールを追加することにより、必要なときにMOC MOCを実行して処理し、出力ファイルを扱うことができます。私たちは、qmakeのメイクファイル生成ツールを使用してメイクファイルを構築することを提案します。このツールは、それが必要なすべてのMOC処理を行い、メイクファイルを生成します。あなたがあなた自身のメイクファイルを作成したい場合は、ここではmocのプロセスを含める方法についていくつかのヒントがあります。Q_OBJECTクラス宣言ヘッダファイルの場合は、あなただけのGNU makeを使用している場合、これは便利なメイクファイルルールは次のとおりです。

moc_%.cpp: %.h
          moc $(DEFINES) $(INCPATH) $< -o $@

あなたは簡単に書きたい場合は、以下のフォームでのルールを使用することができます。

 moc_foo.cpp: foo.h
          moc $(DEFINES) $(INCPATH) $< -o $@

  Moc_foo.cppは、あなたに追加する必要がありSOURCES(お好きな名前に置き換え)、変数、あなたにmoc_foo.oやmoc_foo.obj オブジェクト変数。これらの2つの例では、我々は定義するために渡されたとパスオプションC ++コンパイラが含まれている$(DEFINES)と$(INCPATH)ことを前提としています。前処理ソースファイルにこれらのMOC必要。我々は、C ++ソースファイルには.cppに名前を付けることを好むが、あなたが好むならば、あなたは、.C、.ccに、.CC、.CXXと.C ++などの他の拡張機能を使用することができますが。Q_OBJECTクラス宣言ファイル(.cpp)の実現のために、私たちは次のメイクファイルルールを使用することをお勧めします:

foo.o: foo.moc

foo.moc: foo.cpp
         moc $(DEFINES) $(INCPATH) -i $< -o $@

foo.cppをコンパイルする前に、MOCの実行を行い、この保証。そして、次のことができます

  #include "foo.moc"

foo.cppの終わりには、ファイル内のすべてのクラス宣言は完全に知られています。

コマンドラインオプション

ここでMOCのコマンドラインオプションをサポートするためのいくつかのツールは、次のとおりです。

オプション 説明
-o <ファイル> <ファイル>の代わりに、標準出力に出力を書き込みます。
-f [<ファイル>] 出力で生成されたの#include文の力。これは、ヘッダファイルHまたはHデフォルトの先頭に拡張したものです。あなたのヘッダファイルは、標準の命名規則を満たしていない場合は、このオプションが便利です。節はオプションです。
-私 出力中の#include文を生成しません。これは、クラス宣言で実行するために使用することができますC ++ファイルのMOCの一つ以上が含まれています。あなたは、.cppファイルで、その後の#include元のオブジェクトコードする必要があります。
-nw すべての警告を生成しません。(推奨しません)
-p <パス> モックは、生成されたの#includeステートメントを追加します /ファイル名に。
-I <DIR> ディレクトリ内のヘッダファイルをインクルードするためにパスを追加します。
-E 唯一の前処理;要素は、オブジェクトコードを生成しません。
-D <マクロ> = <DEF>] オプションで定義されたマクロを使用します。
-U マクロを定義しないでください
-M <キー=値> プラグインする追加のメタデータを添付してください。クラスはQ_PLUGIN_METADATAを指定した場合、キーと値のペアは、そのメタデータに追加されます。これは、JSONは、最終的に(アクセスQPluginLoaderから)プラグイン解像度として、実行時にオブジェクトになります。静的な情報が解決に構築ウィジェットシステムをマークするためにこのパラメータは、一般的に使用されます。
@ <ファイル> <ファイル>でから読み取るための他のコマンドラインオプション。ファイルの各行はオプションと考えられています。空白行は無視されます。オプションファイル自体は、このオプション(別のファイルを「含める」ことができない、すなわちオプションファイル)をサポートしていないことに注意してください。
-h 使用方法とオプションのリストを表示します。
-v MOCのバージョン番号を表示します
-Fdir ヘッダファイルの先頭にフレームワークのMacOSディレクトリdirではディレクトリのリストを検索します。-Iオプションで指定されたこれらのディレクトリとディレクトリが(GCCのmanページを参照してください)右スキャン左からずらし、を押します。一般的に、-F /ライブラリ/フレームワーク/

あなたは明示的にヘッダファイルの一部を解決しないMOCを伝えることができます。MOCプリプロセッサシンボルはQ_MOC_RUNを定義しました。

#ifndef Q_MOC_RUN
      ...
#endif

コード間のスキップされます。

診断

  MOCはあなたの文のQ_OBJECTクラスの危険または違法建築の多くを警告します。あなたがプログラムを構築の最終段階でエラーのリンクが発生した場合は、YOURCLASS ::クラス名()が定義されたかYOURCLASSが、その後、エラーをvtableのに欠けていないと述べました。ほとんどの場合、あなたは、生成またはC ++コード、またはリンクコマンド(前者の場合)には、オブジェクトを含むファイルをコンパイルする#include MOCを忘れてしまいました。あなたがqmakeのを使用している場合は、メイクファイルを更新するために、もう一度それを実行してみてください。これは、問題を解決する必要があります。

制限事項

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 ::接続()文字どおりのデータ型を比較します。したがって、アライメントとQt ::アラインメントは、二つの異なるタイプと見なされます。この制限を回避するには、シグナルとスロットを宣言する際に、完全なデータ型を記述し、接続を確立することを確認してください。例えば:

  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();
      };
  };

戻り信号/グルーブ型の値を参照することはできません

信号と溝が戻り値の型を持っていますが、参照を返す禁止します。

クラス内の信号とスロットシグナルとスロット部のみが発生する可能性が

あなたは信号またはシグナルとスロットのクラスの他の構造のタンクの一部としないようにしようとすると、MOCは文句を言うでしょう。

おすすめ

転載: blog.csdn.net/a844651990/article/details/92995452