以下を追加する必要があると思います。
別のリンクされた質問があります-そして、その回答に対する非常に詳細な拡張と見なすことができる非常に優れた記事があります。これがこの記事です、コード構文の強調表示が改善されています (まだ完全ではありません)。
ここに私の短い言い直しがありますが、それは間違いを起こしやすいかもしれません )
基本的に、クラス定義にマクロを挿入するQ_OBJECT
と、プリプロセッサはそれをQMetaObject
同じクラスのすべてのインスタンスで共有される静的インスタンス宣言に展開します。
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
このインスタンスは、初期化時にシグナルとスロットのシグネチャ( ) を保存し、呼び出しを実装できるようにします。これにより、シグネチャ文字列によってメソッドのインデックスが返されます。"methodname(argtype1,argtype2)"
indexOfMethod()
struct Q_CORE_EXPORT QMetaObject
{
// ... skip ...
int indexOfMethod(const char *method) const;
// ... skip ...
static void activate(QObject *sender, int signal_index, void **argv);
// ... skip ...
struct { // private data
const QMetaObject *superdata; // links to the parent class, I guess
const char *stringdata; // basically, "string1\0string2\0..." that contains signatures and other names
const uint *data; // the indices for the strings in stringdata and other stuff (e.g. flags)
// skip
} d;
};
がQtクラス ヘッダーmoc
のファイルを作成すると、構造体の正しい初期化に必要な署名文字列とその他のデータがそこに配置され、このデータを使用してシングルトンの初期化コードが書き込まれます。moc_headername.cpp
headername.h
d
staticMetaObject
もう 1 つの重要なことは、オブジェクトのメソッドのコードの生成です。これはqt_metacall()
、オブジェクトのメソッド ID と引数ポインターの配列を受け取り、次のswitch
ように long を介してメソッドを呼び出します。
int ClassName::qt_metacall(..., int _id, void **_args)
{
// ... skip ...
switch (_id) {
case 0: signalOrSlotMethod1(_args[1], _args[2]); break; // for a method with two args
case 1: signalOrSlotMethod2(_args[1]); break; // for a method with a single argument
// ... etc ...
}
// ... skip ...
}
最後に、 for every signalがcallmoc
を含む実装を生成します:QMetaObject::activate()
void ClassName::signalName(argtype1 arg1, argtype2 arg2, /* ... */)
{
void *_args[] = { 0, // this entry stands for the return value
&arg1, // actually, there's a (void*) type conversion
&arg2, // in the C++ style
// ...
};
QMetaObject::activate( this,
&staticMetaObject,
0, /* this is the signal index in the qt_metacall() map, I suppose */
_args
);
}
最後に、connect()
呼び出しは文字列メソッド シグネチャを整数 ID ( によって使用されるものqt_metacall()
) に変換し、シグナルとスロットの接続のリストを維持します。シグナルが発信されると、コードはこのリストを調べ、メソッドactivate()
を介して適切なオブジェクト「スロット」を呼び出します。qt_metacall()
要約すると、静的QMetaObject
インスタンスは「メタ情報」(メソッド シグネチャ文字列など) を格納し、生成されたqt_metacall()
メソッドは「メソッド テーブル」を提供し、インデックスによって任意のシグナル/スロットを呼び出すことができます。moc
これらのインデックスを使用して生成されたシグナルの実装を介してactivate()
、最後connect()
にシグナルからスロットへのインデックスマップのリストを維持する仕事をします。
*注: 異なるスレッド間でシグナルを配信したい場合に使用されるこのスキームは複雑です (blocking_activate()
コードを確認する必要があると思われます) が、一般的な考え方が同じであることを願っています)
これは、リンクされた記事に対する私の非常に大まかな理解であり、簡単に間違っている可能性があるため、直接読んでみることをお勧めします )
PS。Qt の実装についての理解を深めたいので、私の言い直しに矛盾があれば教えてください。
私の他の(以前の)回答は熱心な編集者によって削除されたため、ここにテキストを追加します(Pavel Shvedの投稿に組み込まれていない詳細がいくつか欠けており、回答を削除した人が気にかけているとは思えません。)
@パベル・シュヴェド:
Qtヘッダーのどこかに次の行があると確信しています:
#define emit
確認するために、Googleコード検索で古いQtコードで見つけました。まだそこにある可能性が高いです); 見つかった場所のパスは次のとおりです:
ftp://ftp.slackware-brasil.com.br › slackware-7.1› contrib› kde-1.90› qt-2.1.1.tgz› usr› lib› qt-2.1.1› src› kernel›
qobjectdefs.h
別の補足リンク: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html -- Andreas Pakulat による回答を参照してください。
Qtの質問:シグナルとスロットはどのように機能しますか?