Wie Signal und Schlitze sind unter der Haube umgesetzt?
-
05-07-2019 - |
Frage
Diese Frage bereits in diesem Forum gefragt, aber ich verstehe nicht, das Konzept.
Ich las sich um und es scheint, dass Signal und Schlitze werden mit Funktionszeigern implementiert das heißt, das Signal ist eine große Funktion, die im Inneren alle angeschlossenen Schlitze (Funktionszeiger) aufruft. Ist das richtig? Und was ist die Rolle der erzeugten moc-Dateien in der ganzen Geschichte? Ich verstehe nicht, wie die Signalfunktion weiß, welche Schlitze nennen heißt, die Schlitze auf dieses Signal verbunden ist.
Vielen Dank für Ihre Zeit
Lösung
Qt implementiert diese Dinge in einer Weise, die interpretierten Sprachen ähnelt. D. h es baut Symboltabellen, die Signalnamen auf Funktionszeiger Karte, hält sie und die Funktionszeiger von Funktionsnamen sucht, wo nötig.
Jedes Mal, wenn Sie ein Signal aussenden, das heißt write
emit something();
Sie die something()
Funktion tatsächlich aufrufen, die sie automatisch vom Metaobjekt-Compiler erzeugt und in eine *.moc
-Datei abgelegt. Innerhalb dieser Funktion wird es überprüft, welche Slots dieses Signal zur Zeit verbunden ist, und entsprechenden Steckplatz Funktionen (die Sie in Ihren eigenen Quellen implementiert) nacheinander über die Symboltabellen genannt (in der oben beschriebenen Weise). Und emit
, wie andere Qt-spezifische Keywords, werden nur von C ++ Präprozessor verworfen, nachdem *.moc
generiert wurden. Tatsächlich in einer der Qt-Header ( qobjectdefs.h ), gibt es solche Zeilen:
#define slots
#define signals protected
#define emit
Verbindungsfunktion (connect
) ändert nur die Symboltabellen innerhalb *.moc
Dateien beibehalten, und die ihm übergebenen Argumente (mit SIGNAL()
und `SCHLITZ-Makros) vorverarbeitet, um auch die Tabellen zu entsprechen.
Das ist die allgemeine Idee. In seiner weiteren Antwort, ジ ョ ー ジ liefert uns Links Mailingliste und auf eine andere Frage SO zu diesem Thema.
Andere Tipps
Ich glaube, ich sollte die folgende hinzuzufügen.
Es gibt anderen verbunden Frage - und es gibt < a href = "http://www.ntcore.com/files/qtrev.htm" rel = "nofollow noreferrer"> ein sehr guter Artikel dass als recht detailliert Expansion es ist answer ; hier ist dieser Artikel wieder , mit verbessertem (wenn auch noch nicht perfekt) Code Syntaxhervorhebung.
Hier ist meine kurze Nacherzählung davon, dass auf Fehler anfällig sein kann)
Im Grunde genommen, wenn wir die Q_OBJECT
Makro in unserer Klassendefinition einfügen, der Präprozessor es zu einer statischen QMetaObject
Instanz Erklärung erweitert, eine, die von allen Instanzen der gleichen Klasse geteilt werden würde:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
Dieses Beispiel wiederum wird bei der Initialisierung speichern Sie die Signaturen ("methodname(argtype1,argtype2)"
) der Signale und die Schlitze, welche den indexOfMethod()
Anruf erlaubt zu implementieren, die durch sie, na ja, Methode des Index zurückgibt ist Unterschrift string:
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;
};
Nun, wenn die moc
die moc_headername.cpp
Datei für die Klasse-Header headername.h
Qt schafft, bringt es gibt die Signatur Strings und andere Daten, die für die korrekte Initialisierung der d
Struktur erforderlich sind, und schreibt dann den Initialisierungscode für die staticMetaObject
Singletons dies mit Daten.
Eine weitere wichtige Sache, die es tut, ist die Erzeugung des Code für die qt_metacall()
Methode des Objekts, das die Methode eines Objektes ID und eine Reihe von Argumentzeiger und ruft die Methode über eine lange switch
wie dies geschieht:
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 ...
}
Last, für jedes Signal moc
erzeugt eine Implementierung, die einen QMetaObject::activate()
Aufruf enthält:
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
);
}
Schließlich übersetzt der connect()
Aufruf die Zeichenfolge Methodensignaturen, um ihre ganze Zahl IDs (die durch qt_metacall()
verwendet sind) und führt eine Liste der Signal-zu-Slot-Verbindungen; wenn das Signal ausgesendet wird, geht der activate()
Code durch diese Liste und ruft die entsprechende Objekt „Slots“ über ihre qt_metacall()
Methode.
Um es zusammenzufassen, die statische QMetaObject
Instanz speichert die „Meta-Informationen“ (Methodensignatur Strings usw.), eine erzeugte qt_metacall()
Verfahren sieht „eine Methodentabelle“, die jedes Signal / Schlitz ermöglicht durch einen Index, Signal Implementierungen aufgerufen werden von moc
erzeugt diese Indizes über activate()
verwenden, und schließlich connect()
macht den Job der Liste Signal-Slot-Index Karten beibehalten wird.
* Hinweis: Es gibt eine Komplikation dieser Regelung für den Fall verwendet werden, wenn wir Signale zwischen verschiedenen Threads liefern wollen (ich vermute, dass man an dem blocking_activate()
Code aussehen muss), aber ich hoffe, dass die allgemeine Idee gleich bleibt)
Das ist mein sehr grobes Verständnis der verlinkten Artikel, die leicht falsch sein können, so dass ich nicht empfehle es direkt zu gehen und lesen)
PS. Als ich mein Verständnis von Qt Umsetzung verbessern möchten - lassen Sie es mich in meiner Nacherzählung von Widersprüchen kennen
Da meine anderen (früher) Antwort von einigen eifrigen Editor gelöscht wurde, werde ich den Text hier anhängen (Ich vermisse einige Details, die waren nicht integriert in Pavel Shved der Post, und ich bezweifle, die Person die gelöscht die Antwort gepflegt.)
@Pavel Shved:
Ich bin ziemlich sicher, dass irgendwo in Qt-Header eine Zeile vorhanden ist:
#define emit
Just zu bestätigen: fand es in alten Qt-Code von Google Code Search. Es ist sehr wahrscheinlich, dass es noch da ist); die gefundene location Weg war:
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
Ein weiterer complementory Link: http: //lists.trolltech .com / qt-interest / 2007-05 / thread00691-0.html - siehe die Antwort von Andreas Pakulat
Und hier ist ein weiteres Stück der Antwort: Qt Frage: Wie Signale und Slots arbeiten