Je pense que je devrais ajouter ce qui suit.
Il y a another linked question - et il y a a very good article qui peut être considéré comme une expansion assez détaillée à answer; here is this article again, avec amélioration de la syntaxe du code (mais pas toujours parfaite).
Voici mon court récit de celui-ci, qui peuvent être sujettes à des erreurs)
Fondamentalement quand nous insérons la Q_OBJECT
macro dans notre définition de la classe, le préprocesseur se dilate à une déclaration QMetaObject
d'instance statique, qui serait partagé par toutes les instances de la même classe:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
Cette instance, à son tour, lors de l'initialisation stocke les signatures ("methodname(argtype1,argtype2)"
) des signaux et les machines à sous, ce qui permettra de mettre en œuvre le indexOfMethod()
appel, ce qui revient, eh bien, l'indice de la méthode par sa chaîne de signature:
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;
};
Maintenant, lorsque le moc
crée le fichier moc_headername.cpp
pour l'en-tête de classe Qt headername.h
, il y met les chaînes de signature et d'autres données qui sont nécessaires pour initialisation correcte de la structure d
, puis écrit le code d'initialisation pour le singleton staticMetaObject
en utilisant ces données.
Une autre chose importante qu'il fait est la génération du code pour la méthode qt_metacall()
de l'objet, qui prend l'ID de méthode d'un objet et un tableau de pointeurs d'argument et appelle la méthode par une longue switch
comme ceci:
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 ...
}
Enfin, pour tous les signaux moc
génère une mise en œuvre, qui contient un appel 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
);
}
Enfin, l'appel connect()
traduit le STRI ng les signatures de méthode à leurs identifiants entiers (ceux utilisés par qt_metacall()
) et gère une liste de connexions signal-emplacement; lorsque le signal est émis, le code activate()
passe par cette liste et appelle l'objet approprié "slots" via sa méthode qt_metacall()
. Pour résumer, l'instance statique QMetaObject
stocke les "méta-informations" (chaînes de signature de méthode, etc.), une méthode générée qt_metacall()
fournit "une table de méthodes" qui permet à n'importe quel signal/emplacement d'être appelé par un index, signal implémentations générées par moc
utilisent ces index via activate()
, et finalement connect()
fait le travail de maintenir une liste de cartes d'index de signal-à-logement. * Note: il y a une complication de ce schéma utilisé dans le cas où l'on veut délivrer des signaux entre différents threads (je suppose qu'on doit regarder le code blocking_activate()
), mais j'espère que l'idée générale reste la même)
Ceci est ma compréhension très approximative de l'article lié, ce qui peut facilement se tromper, donc je ne recommande d'aller lire directement)
PS. Comme je voudrais améliorer ma compréhension de la mise en œuvre de Qt - s'il vous plaît laissez-moi savoir des incohérences dans mon récit!
Depuis mon autre (plus tôt) réponse a été supprimée par un éditeur zélé, je vais ajouter le texte ici (je manque quelques détails qui étaient pas incorporés dans le poste de Pavel Shved, et je doute la personne qui supprimé la réponse se souciait.)
@Pavel Shved:
Je suis assez sûr que quelque part en tête de Qt existe-t-il une ligne:
#define emit
Juste pour confirmer: trouvé dans l'ancien code Qt par Google Code Search. Il est fort probable qu'il soit toujours là); le chemin de l'emplacement trouvé était:
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> noyau> qobjectdefs.h
Un autre lien complementory: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html - voir la réponse par Andreas Pakulat
Et voici un autre morceau de la réponse: Qt question: How do signals and slots work?
question Nice. Voir aussi: http://stackoverflow.com/questions/1413777/how-boost-implements-signals-and-slots – elcuco